@ionic/core 8.3.4-nightly.20241024 → 8.3.4-nightly.20241028

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 (84) hide show
  1. package/components/ion-input.js +20 -5
  2. package/components/ion-textarea.js +19 -4
  3. package/components/overlays.js +62 -7
  4. package/dist/cjs/index.cjs.js +1 -1
  5. package/dist/cjs/ion-action-sheet.cjs.entry.js +1 -1
  6. package/dist/cjs/ion-alert.cjs.entry.js +1 -1
  7. package/dist/cjs/ion-datetime_3.cjs.entry.js +1 -1
  8. package/dist/cjs/ion-input.cjs.entry.js +20 -5
  9. package/dist/cjs/ion-loading.cjs.entry.js +1 -1
  10. package/dist/cjs/ion-menu_3.cjs.entry.js +1 -1
  11. package/dist/cjs/ion-modal.cjs.entry.js +1 -1
  12. package/dist/cjs/ion-popover.cjs.entry.js +1 -1
  13. package/dist/cjs/ion-select_3.cjs.entry.js +1 -1
  14. package/dist/cjs/ion-textarea.cjs.entry.js +19 -4
  15. package/dist/cjs/ion-toast.cjs.entry.js +1 -1
  16. package/dist/cjs/{overlays-0123d7d4.js → overlays-ba0f6986.js} +62 -7
  17. package/dist/collection/components/input/input.js +20 -5
  18. package/dist/collection/components/textarea/textarea.js +19 -4
  19. package/dist/collection/utils/overlays.js +62 -7
  20. package/dist/docs.json +1 -1
  21. package/dist/esm/index.js +1 -1
  22. package/dist/esm/ion-action-sheet.entry.js +1 -1
  23. package/dist/esm/ion-alert.entry.js +1 -1
  24. package/dist/esm/ion-datetime_3.entry.js +1 -1
  25. package/dist/esm/ion-input.entry.js +20 -5
  26. package/dist/esm/ion-loading.entry.js +1 -1
  27. package/dist/esm/ion-menu_3.entry.js +1 -1
  28. package/dist/esm/ion-modal.entry.js +1 -1
  29. package/dist/esm/ion-popover.entry.js +1 -1
  30. package/dist/esm/ion-select_3.entry.js +1 -1
  31. package/dist/esm/ion-textarea.entry.js +19 -4
  32. package/dist/esm/ion-toast.entry.js +1 -1
  33. package/dist/esm/{overlays-9c75ec54.js → overlays-ae10d43d.js} +62 -7
  34. package/dist/esm-es5/index.js +1 -1
  35. package/dist/esm-es5/ion-action-sheet.entry.js +1 -1
  36. package/dist/esm-es5/ion-alert.entry.js +1 -1
  37. package/dist/esm-es5/ion-datetime_3.entry.js +1 -1
  38. package/dist/esm-es5/ion-input.entry.js +1 -1
  39. package/dist/esm-es5/ion-loading.entry.js +1 -1
  40. package/dist/esm-es5/ion-menu_3.entry.js +1 -1
  41. package/dist/esm-es5/ion-modal.entry.js +1 -1
  42. package/dist/esm-es5/ion-popover.entry.js +1 -1
  43. package/dist/esm-es5/ion-select_3.entry.js +1 -1
  44. package/dist/esm-es5/ion-textarea.entry.js +1 -1
  45. package/dist/esm-es5/ion-toast.entry.js +1 -1
  46. package/dist/esm-es5/overlays-ae10d43d.js +4 -0
  47. package/dist/ionic/index.esm.js +1 -1
  48. package/dist/ionic/ionic.esm.js +1 -1
  49. package/dist/ionic/p-04fc24ee.system.js +4 -0
  50. package/dist/ionic/{p-b4c950f8.entry.js → p-0c7e32d6.entry.js} +1 -1
  51. package/dist/ionic/{p-100b83fd.system.entry.js → p-110e03be.system.entry.js} +1 -1
  52. package/dist/ionic/p-148b8abb.entry.js +4 -0
  53. package/dist/ionic/{p-4b0fedb7.system.entry.js → p-18105026.system.entry.js} +1 -1
  54. package/dist/ionic/{p-f50ae0d5.system.entry.js → p-2031811e.system.entry.js} +1 -1
  55. package/dist/ionic/{p-cff5585e.system.entry.js → p-2dc74eb3.system.entry.js} +1 -1
  56. package/dist/ionic/p-322c5fb4.system.js +1 -1
  57. package/dist/ionic/p-5c831f49.js +4 -0
  58. package/dist/ionic/{p-a72fb8a1.system.entry.js → p-63d65dbc.system.entry.js} +1 -1
  59. package/dist/ionic/{p-9fef1364.entry.js → p-6d50faff.entry.js} +1 -1
  60. package/dist/ionic/{p-a4d51b8d.system.js → p-79b12fda.system.js} +1 -1
  61. package/dist/ionic/{p-8ed31163.system.entry.js → p-79e7be3a.system.entry.js} +1 -1
  62. package/dist/ionic/{p-7c50965e.entry.js → p-8640e9cd.entry.js} +1 -1
  63. package/dist/ionic/{p-9c23044d.entry.js → p-87a4407b.entry.js} +1 -1
  64. package/dist/ionic/{p-a41699db.entry.js → p-8ff21f38.entry.js} +1 -1
  65. package/dist/ionic/{p-b0568945.system.entry.js → p-921e159f.system.entry.js} +1 -1
  66. package/dist/ionic/{p-2b7c93b4.entry.js → p-9895e7f3.entry.js} +1 -1
  67. package/dist/ionic/{p-5e66bcf2.entry.js → p-9e208825.entry.js} +1 -1
  68. package/dist/ionic/{p-755b27f0.system.entry.js → p-be715dd3.system.entry.js} +1 -1
  69. package/dist/ionic/{p-22c020db.system.entry.js → p-c3cd6947.system.entry.js} +1 -1
  70. package/dist/ionic/{p-0fa0c92b.entry.js → p-c444705a.entry.js} +1 -1
  71. package/dist/ionic/{p-d77e12ca.entry.js → p-d5abc4b3.entry.js} +1 -1
  72. package/dist/ionic/p-dda5c73d.entry.js +4 -0
  73. package/dist/ionic/{p-9cc3bcc5.system.entry.js → p-f0ab13a8.system.entry.js} +1 -1
  74. package/dist/ionic/{p-ecb57d24.system.entry.js → p-fd2f3a15.system.entry.js} +1 -1
  75. package/dist/types/components/input/input.d.ts +3 -0
  76. package/dist/types/components/textarea/textarea.d.ts +3 -0
  77. package/hydrate/index.js +101 -16
  78. package/hydrate/index.mjs +101 -16
  79. package/package.json +1 -1
  80. package/dist/esm-es5/overlays-9c75ec54.js +0 -4
  81. package/dist/ionic/p-2c4bdd9d.entry.js +0 -4
  82. package/dist/ionic/p-98871496.system.js +0 -4
  83. package/dist/ionic/p-a440397c.js +0 -4
  84. package/dist/ionic/p-bfa2e81c.entry.js +0 -4
@@ -19,6 +19,8 @@ import { getCounterText } from "./input.utils";
19
19
  export class Input {
20
20
  constructor() {
21
21
  this.inputId = `ion-input-${inputIds++}`;
22
+ this.helperTextId = `${this.inputId}-helper-text`;
23
+ this.errorTextId = `${this.inputId}-error-text`;
22
24
  this.inheritedAttributes = {};
23
25
  this.isComposing = false;
24
26
  /**
@@ -291,8 +293,21 @@ export class Input {
291
293
  * Renders the helper text or error text values
292
294
  */
293
295
  renderHintText() {
294
- const { helperText, errorText } = this;
295
- return [h("div", { class: "helper-text" }, helperText), h("div", { class: "error-text" }, errorText)];
296
+ const { helperText, errorText, helperTextId, errorTextId } = this;
297
+ return [
298
+ h("div", { id: helperTextId, class: "helper-text" }, helperText),
299
+ h("div", { id: errorTextId, class: "error-text" }, errorText),
300
+ ];
301
+ }
302
+ getHintTextID() {
303
+ const { el, helperText, errorText, helperTextId, errorTextId } = this;
304
+ if (el.classList.contains('ion-touched') && el.classList.contains('ion-invalid') && errorText) {
305
+ return errorTextId;
306
+ }
307
+ if (helperText) {
308
+ return helperTextId;
309
+ }
310
+ return undefined;
296
311
  }
297
312
  renderCounter() {
298
313
  const { counter, maxlength, counterFormatter, value } = this;
@@ -399,7 +414,7 @@ export class Input {
399
414
  * TODO(FW-5592): Remove hasStartEndSlots condition
400
415
  */
401
416
  const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || hasFocus || hasStartEndSlots));
402
- return (h(Host, { key: '907ce98a82b5cfae5a08504cd79e00a2330b7444', class: createColorClasses(this.color, {
417
+ return (h(Host, { key: 'cdde9963d71685e6a4f3f3b3bc52e75d022435cb', class: createColorClasses(this.color, {
403
418
  [mode]: true,
404
419
  'has-value': hasValue,
405
420
  'has-focus': hasFocus,
@@ -410,7 +425,7 @@ export class Input {
410
425
  'in-item': inItem,
411
426
  'in-item-color': hostContext('ion-item.ion-color', this.el),
412
427
  'input-disabled': disabled,
413
- }) }, h("label", { key: '59d5bb45d2a5b828bba0ed8687a632a551e2f4d8', class: "input-wrapper", htmlFor: inputId }, this.renderLabelContainer(), h("div", { key: 'f93f129d08246d0e9a601c100d718534d6403853', class: "native-wrapper" }, h("slot", { key: '54eeb1a6bace662b7eb0d7e27180ea3d7e3a3729', name: "start" }), h("input", Object.assign({ key: 'b3e0be55bc1a4a539ae3b0fdcf7fc078723cca16', class: "native-input", ref: (input) => (this.nativeInput = input), id: inputId, disabled: disabled, autoCapitalize: this.autocapitalize, autoComplete: this.autocomplete, autoCorrect: this.autocorrect, autoFocus: this.autofocus, enterKeyHint: this.enterkeyhint, inputMode: this.inputmode, min: this.min, max: this.max, minLength: this.minlength, maxLength: this.maxlength, multiple: this.multiple, name: this.name, pattern: this.pattern, placeholder: this.placeholder || '', readOnly: readonly, required: this.required, spellcheck: this.spellcheck, step: this.step, type: this.type, value: value, onInput: this.onInput, onChange: this.onChange, onBlur: this.onBlur, onFocus: this.onFocus, onKeyDown: this.onKeydown, onCompositionstart: this.onCompositionStart, onCompositionend: this.onCompositionEnd }, this.inheritedAttributes)), this.clearInput && !readonly && !disabled && (h("button", { key: '5f6373504a6d0d074bfbf875c794d45ea2748175', "aria-label": "reset", type: "button", class: "input-clear-icon", onPointerDown: (ev) => {
428
+ }) }, h("label", { key: '4412791c93405f20e50e50363879265180b6078f', class: "input-wrapper", htmlFor: inputId }, this.renderLabelContainer(), h("div", { key: '5c71c43ef3eeb44dde76ed64ce10763834c8fbc7', class: "native-wrapper" }, h("slot", { key: '1d86b58dc299a4208dd02ccdc9ceaea7576698c3', name: "start" }), h("input", Object.assign({ key: '7fc932174485f7d09e6a797dfd49ea11fbad71b6', class: "native-input", ref: (input) => (this.nativeInput = input), id: inputId, disabled: disabled, autoCapitalize: this.autocapitalize, autoComplete: this.autocomplete, autoCorrect: this.autocorrect, autoFocus: this.autofocus, enterKeyHint: this.enterkeyhint, inputMode: this.inputmode, min: this.min, max: this.max, minLength: this.minlength, maxLength: this.maxlength, multiple: this.multiple, name: this.name, pattern: this.pattern, placeholder: this.placeholder || '', readOnly: readonly, required: this.required, spellcheck: this.spellcheck, step: this.step, type: this.type, value: value, onInput: this.onInput, onChange: this.onChange, onBlur: this.onBlur, onFocus: this.onFocus, onKeyDown: this.onKeydown, onCompositionstart: this.onCompositionStart, onCompositionend: this.onCompositionEnd, "aria-describedby": this.getHintTextID(), "aria-invalid": this.getHintTextID() === this.errorTextId }, this.inheritedAttributes)), this.clearInput && !readonly && !disabled && (h("button", { key: '46de455e4e308b8d7640b04778f7c7559b4124c6', "aria-label": "reset", type: "button", class: "input-clear-icon", onPointerDown: (ev) => {
414
429
  /**
415
430
  * This prevents mobile browsers from
416
431
  * blurring the input when the clear
@@ -425,7 +440,7 @@ export class Input {
425
440
  * for screen readers as it means users would be unable to swipe past the clear button.
426
441
  */
427
442
  ev.stopPropagation();
428
- }, onClick: this.clearTextInput }, h("ion-icon", { key: '230d77973aa83458ceb32bf52e3abe9bc322cfe6', "aria-hidden": "true", icon: clearIconData }))), h("slot", { key: '9d69ac6e8a3c4b2b303dba2478f82695d5755ed2', name: "end" })), shouldRenderHighlight && h("div", { key: 'ac61f16237ce731e0745ab72d0fc3f066252464a', class: "input-highlight" })), this.renderBottomContent()));
443
+ }, onClick: this.clearTextInput }, h("ion-icon", { key: '375e860a20e1807ce0db0e1934a0650fe9929966', "aria-hidden": "true", icon: clearIconData }))), h("slot", { key: '859d47a1b88aa8377479e5d11e52a6a1c1c30e7e', name: "end" })), shouldRenderHighlight && h("div", { key: 'd2d4286b348107e33247b5c0afda0f8bd697ecee', class: "input-highlight" })), this.renderBottomContent()));
429
444
  }
430
445
  static get is() { return "ion-input"; }
431
446
  static get encapsulation() { return "scoped"; }
@@ -18,6 +18,8 @@ import { getCounterText } from "../input/input.utils";
18
18
  export class Textarea {
19
19
  constructor() {
20
20
  this.inputId = `ion-textarea-${textareaIds++}`;
21
+ this.helperTextId = `${this.inputId}-helper-text`;
22
+ this.errorTextId = `${this.inputId}-error-text`;
21
23
  /**
22
24
  * `true` if the textarea was cleared as a result of the user typing
23
25
  * with `clearOnEdit` enabled.
@@ -305,8 +307,21 @@ export class Textarea {
305
307
  * Renders the helper text or error text values
306
308
  */
307
309
  renderHintText() {
308
- const { helperText, errorText } = this;
309
- return [h("div", { class: "helper-text" }, helperText), h("div", { class: "error-text" }, errorText)];
310
+ const { helperText, errorText, helperTextId, errorTextId } = this;
311
+ return [
312
+ h("div", { id: helperTextId, class: "helper-text" }, helperText),
313
+ h("div", { id: errorTextId, class: "error-text" }, errorText),
314
+ ];
315
+ }
316
+ getHintTextID() {
317
+ const { el, helperText, errorText, helperTextId, errorTextId } = this;
318
+ if (el.classList.contains('ion-touched') && el.classList.contains('ion-invalid') && errorText) {
319
+ return errorTextId;
320
+ }
321
+ if (helperText) {
322
+ return helperTextId;
323
+ }
324
+ return undefined;
310
325
  }
311
326
  renderCounter() {
312
327
  const { counter, maxlength, counterFormatter, value } = this;
@@ -359,7 +374,7 @@ export class Textarea {
359
374
  * TODO(FW-5592): Remove hasStartEndSlots condition
360
375
  */
361
376
  const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || hasFocus || hasStartEndSlots));
362
- return (h(Host, { key: '37595a18d77dea1a337ac1c672e5f08a4128111d', class: createColorClasses(this.color, {
377
+ return (h(Host, { key: 'e8a5b5727c6a018bbd6f5507b690bc5f0959e352', class: createColorClasses(this.color, {
363
378
  [mode]: true,
364
379
  'has-value': hasValue,
365
380
  'has-focus': hasFocus,
@@ -368,7 +383,7 @@ export class Textarea {
368
383
  [`textarea-shape-${shape}`]: shape !== undefined,
369
384
  [`textarea-label-placement-${labelPlacement}`]: true,
370
385
  'textarea-disabled': disabled,
371
- }) }, h("label", { key: '67342758743e5a40448a32ff695876d39778621f', class: "textarea-wrapper", htmlFor: inputId }, this.renderLabelContainer(), h("div", { key: 'a994be8264bf5652811cf816d79a04178954e83f', class: "textarea-wrapper-inner" }, h("div", { key: 'e09c93ebcd5b3d227d51e682ca23dfc7fd7027ad', class: "start-slot-wrapper" }, h("slot", { key: 'd39758f21f19ae70aea21e9a9a7b7c20991fe593', name: "start" })), h("div", { key: '6a4e10e53de4bb235ee30def4c9ae5bdee888816', class: "native-wrapper", ref: (el) => (this.textareaWrapper = el) }, h("textarea", Object.assign({ key: '9e254e551f124d972e9bc6b09ef0f2bb55890be5', class: "native-textarea", ref: (el) => (this.nativeInput = el), id: inputId, disabled: disabled, autoCapitalize: this.autocapitalize, autoFocus: this.autofocus, enterKeyHint: this.enterkeyhint, inputMode: this.inputmode, minLength: this.minlength, maxLength: this.maxlength, name: this.name, placeholder: this.placeholder || '', readOnly: this.readonly, required: this.required, spellcheck: this.spellcheck, cols: this.cols, rows: this.rows, wrap: this.wrap, onInput: this.onInput, onChange: this.onChange, onBlur: this.onBlur, onFocus: this.onFocus, onKeyDown: this.onKeyDown }, this.inheritedAttributes), value)), h("div", { key: 'a66aa2d2bc4778a0bec56a8b9ec9052a832eb3b2', class: "end-slot-wrapper" }, h("slot", { key: '8e6a90b4475de32e23afc593da4108610dcca663', name: "end" }))), shouldRenderHighlight && h("div", { key: '6da03205a8daff45581b20f0af3938634a9d5f8c', class: "textarea-highlight" })), this.renderBottomContent()));
386
+ }) }, h("label", { key: '48e889571e2d3e7e150b038e4b4b15862b418288', class: "textarea-wrapper", htmlFor: inputId }, this.renderLabelContainer(), h("div", { key: '6c6c7872ae4d351d8b8d772ad18ce3ba7a0e9a87', class: "textarea-wrapper-inner" }, h("div", { key: '03aef5dfa59af0fa78a3e5c92e0ed72396717d72', class: "start-slot-wrapper" }, h("slot", { key: '39aee9faebb0f1d10de5a5817fd9d9771b074b96', name: "start" })), h("div", { key: '738e8ff603f4c9b9083b3139db861f4b7ec20f79', class: "native-wrapper", ref: (el) => (this.textareaWrapper = el) }, h("textarea", Object.assign({ key: '7763fb4f8ffe94635167331c70d21d661544c4f8', class: "native-textarea", ref: (el) => (this.nativeInput = el), id: inputId, disabled: disabled, autoCapitalize: this.autocapitalize, autoFocus: this.autofocus, enterKeyHint: this.enterkeyhint, inputMode: this.inputmode, minLength: this.minlength, maxLength: this.maxlength, name: this.name, placeholder: this.placeholder || '', readOnly: this.readonly, required: this.required, spellcheck: this.spellcheck, cols: this.cols, rows: this.rows, wrap: this.wrap, onInput: this.onInput, onChange: this.onChange, onBlur: this.onBlur, onFocus: this.onFocus, onKeyDown: this.onKeyDown, "aria-describedby": this.getHintTextID(), "aria-invalid": this.getHintTextID() === this.errorTextId }, this.inheritedAttributes), value)), h("div", { key: 'b3af9ec0982c6dbd381afaa02df153d7e90471be', class: "end-slot-wrapper" }, h("slot", { key: '60f99bcd49a5ec2e1fa6e3e77809aefeb9d2d0d6', name: "end" }))), shouldRenderHighlight && h("div", { key: '6a7f45639ba027f4da573adae53f1197a6dec383', class: "textarea-highlight" })), this.renderBottomContent()));
372
387
  }
373
388
  static get is() { return "ion-textarea"; }
374
389
  static get encapsulation() { return "scoped"; }
@@ -427,9 +427,19 @@ export const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation
427
427
  if (overlay.presented) {
428
428
  return;
429
429
  }
430
- setRootAriaHidden(true);
430
+ /**
431
+ * Due to accessibility guidelines, toasts do not have
432
+ * focus traps.
433
+ *
434
+ * All other overlays should have focus traps to prevent
435
+ * the keyboard focus from leaving the overlay.
436
+ */
437
+ if (overlay.el.tagName !== 'ION-TOAST') {
438
+ setRootAriaHidden(true);
439
+ }
431
440
  document.body.classList.add(BACKDROP_NO_SCROLL);
432
- hideOverlaysFromScreenReaders(overlay.el);
441
+ hideUnderlyingOverlaysFromScreenReaders(overlay.el);
442
+ hideAnimatingOverlayFromScreenReaders(overlay.el);
433
443
  overlay.presented = true;
434
444
  overlay.willPresent.emit();
435
445
  (_a = overlay.willPresentShorthand) === null || _a === void 0 ? void 0 : _a.emit();
@@ -469,6 +479,11 @@ export const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation
469
479
  * it would still have aria-hidden on being presented again.
470
480
  * Removing it here ensures the overlay is visible to screen
471
481
  * readers.
482
+ *
483
+ * If this overlay was being presented, then it was hidden
484
+ * from screen readers during the animation. Now that the
485
+ * animation is complete, we can reveal the overlay to
486
+ * screen readers.
472
487
  */
473
488
  overlay.el.removeAttribute('aria-hidden');
474
489
  };
@@ -526,17 +541,35 @@ export const dismiss = async (overlay, data, role, name, iosLeaveAnimation, mdLe
526
541
  if (!overlay.presented) {
527
542
  return false;
528
543
  }
529
- const lastOverlay = doc !== undefined && getPresentedOverlays(doc).length === 1;
530
544
  /**
531
- * If this is the last visible overlay then
532
- * we want to re-add the root to the accessibility tree.
545
+ * For accessibility, toasts lack focus traps and don’t receive
546
+ * `aria-hidden` on the root element when presented.
547
+ *
548
+ * All other overlays use focus traps to keep keyboard focus
549
+ * within the overlay, setting `aria-hidden` on the root element
550
+ * to enhance accessibility.
551
+ *
552
+ * Therefore, we must remove `aria-hidden` from the root element
553
+ * when the last non-toast overlay is dismissed.
533
554
  */
534
- if (lastOverlay) {
555
+ const overlaysNotToast = doc !== undefined ? getPresentedOverlays(doc).filter((o) => o.tagName !== 'ION-TOAST') : [];
556
+ const lastOverlayNotToast = overlaysNotToast.length === 1 && overlaysNotToast[0].id === overlay.el.id;
557
+ /**
558
+ * If this is the last visible overlay that is not a toast
559
+ * then we want to re-add the root to the accessibility tree.
560
+ */
561
+ if (lastOverlayNotToast) {
535
562
  setRootAriaHidden(false);
536
563
  document.body.classList.remove(BACKDROP_NO_SCROLL);
537
564
  }
538
565
  overlay.presented = false;
539
566
  try {
567
+ /**
568
+ * There is no need to show the overlay to screen readers during
569
+ * the dismiss animation. This is because the overlay will be removed
570
+ * from the DOM after the animation is complete.
571
+ */
572
+ hideAnimatingOverlayFromScreenReaders(overlay.el);
540
573
  // Overlay contents should not be clickable during dismiss
541
574
  overlay.el.style.setProperty('pointer-events', 'none');
542
575
  overlay.willDismiss.emit({ data, role });
@@ -771,6 +804,28 @@ export const createTriggerController = () => {
771
804
  removeClickListener,
772
805
  };
773
806
  };
807
+ /**
808
+ * The overlay that is being animated also needs to hide from screen
809
+ * readers during its animation. This ensures that assistive technologies
810
+ * like TalkBack do not announce or interact with the content until the
811
+ * animation is complete, avoiding confusion for users.
812
+ *
813
+ * If the overlay is being presented, it prevents focus rings from appearing
814
+ * in incorrect positions due to the transition (specifically `transform`
815
+ * styles), ensuring that when aria-hidden is removed, the focus rings are
816
+ * correctly displayed in the final location of the elements.
817
+ *
818
+ * @param overlay - The overlay that is being animated.
819
+ */
820
+ const hideAnimatingOverlayFromScreenReaders = (overlay) => {
821
+ if (doc === undefined)
822
+ return;
823
+ /**
824
+ * Once the animation is complete, this attribute will be removed.
825
+ * This is done at the end of the `present` method.
826
+ */
827
+ overlay.setAttribute('aria-hidden', 'true');
828
+ };
774
829
  /**
775
830
  * Ensure that underlying overlays have aria-hidden if necessary so that screen readers
776
831
  * cannot move focus to these elements. Note that we cannot rely on focus/focusin/focusout
@@ -781,7 +836,7 @@ export const createTriggerController = () => {
781
836
  * @param newTopMostOverlay - The overlay that is being presented. Since the overlay has not been
782
837
  * fully presented yet at the time this function is called it will not be included in the getPresentedOverlays result.
783
838
  */
784
- const hideOverlaysFromScreenReaders = (newTopMostOverlay) => {
839
+ const hideUnderlyingOverlaysFromScreenReaders = (newTopMostOverlay) => {
785
840
  var _a;
786
841
  if (doc === undefined)
787
842
  return;
package/dist/docs.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2024-10-24T06:09:22",
2
+ "timestamp": "2024-10-28T06:10:05",
3
3
  "compiler": {
4
4
  "name": "@stencil/core",
5
5
  "version": "4.20.0",
package/dist/esm/index.js CHANGED
@@ -12,7 +12,7 @@ export { c as componentOnReady } from './helpers-da915de8.js';
12
12
  export { I as IonicSafeString, g as getMode, s as setupConfig } from './config-49c88215.js';
13
13
  export { o as openURL } from './theme-01f3f29c.js';
14
14
  export { m as menuController } from './index-fe1782b1.js';
15
- export { b as actionSheetController, a as alertController, l as loadingController, m as modalController, p as pickerController, c as popoverController, t as toastController } from './overlays-9c75ec54.js';
15
+ export { b as actionSheetController, a as alertController, l as loadingController, m as modalController, p as pickerController, c as popoverController, t as toastController } from './overlays-ae10d43d.js';
16
16
  import './index-a5d50daf.js';
17
17
  import './index-28849c61.js';
18
18
  import './index-9b0d46f4.js';
@@ -5,7 +5,7 @@ import { r as registerInstance, d as createEvent, e as readTask, h, f as Host, i
5
5
  import { c as createButtonActiveGesture } from './button-active-f6503382.js';
6
6
  import { r as raf } from './helpers-da915de8.js';
7
7
  import { c as createLockController } from './lock-controller-316928be.js';
8
- import { d as createDelegateController, e as createTriggerController, B as BACKDROP, i as isCancel, f as present, g as dismiss, h as eventMethod, s as safeCall, j as prepareOverlay, k as setOverlayId } from './overlays-9c75ec54.js';
8
+ import { d as createDelegateController, e as createTriggerController, B as BACKDROP, i as isCancel, f as present, g as dismiss, h as eventMethod, s as safeCall, j as prepareOverlay, k as setOverlayId } from './overlays-ae10d43d.js';
9
9
  import { g as getClassMap } from './theme-01f3f29c.js';
10
10
  import { b as getIonMode } from './ionic-global-c81d82ab.js';
11
11
  import { c as createAnimation } from './animation-eab5a4ca.js';
@@ -6,7 +6,7 @@ import { E as ENABLE_HTML_CONTENT_DEFAULT, a as sanitizeDOMString } from './conf
6
6
  import { c as createButtonActiveGesture } from './button-active-f6503382.js';
7
7
  import { r as raf } from './helpers-da915de8.js';
8
8
  import { c as createLockController } from './lock-controller-316928be.js';
9
- import { d as createDelegateController, e as createTriggerController, B as BACKDROP, i as isCancel, j as prepareOverlay, k as setOverlayId, f as present, g as dismiss, h as eventMethod, s as safeCall } from './overlays-9c75ec54.js';
9
+ import { d as createDelegateController, e as createTriggerController, B as BACKDROP, i as isCancel, j as prepareOverlay, k as setOverlayId, f as present, g as dismiss, h as eventMethod, s as safeCall } from './overlays-ae10d43d.js';
10
10
  import { g as getClassMap } from './theme-01f3f29c.js';
11
11
  import { c as config, b as getIonMode } from './ionic-global-c81d82ab.js';
12
12
  import { c as createAnimation } from './animation-eab5a4ca.js';
@@ -11,7 +11,7 @@ import { c as chevronBack, o as chevronForward, l as chevronDown, p as caretUpSh
11
11
  import { b as getIonMode } from './ionic-global-c81d82ab.js';
12
12
  import { g as generateDayAriaLabel, a as getDay, i as isBefore, b as isAfter, c as isSameDay, d as getPreviousMonth, e as getNextMonth, v as validateParts, f as getPartsFromCalendarDay, h as getNextYear, j as getPreviousYear, k as getEndOfWeek, l as getStartOfWeek, m as getPreviousDay, n as getNextDay, o as getPreviousWeek, p as getNextWeek, q as parseMinParts, r as parseMaxParts, s as parseDate, w as warnIfValueOutOfBounds, t as convertToArrayOfNumbers, u as convertDataToISO, x as getToday, y as getClosestValidDate, z as generateMonths, A as getNumDaysInMonth, B as getCombinedDateColumnData, C as getMonthColumnData, D as getDayColumnData, E as getYearColumnData, F as isMonthFirstLocale, G as getTimeColumnsData, H as isLocaleDayPeriodRTL, I as getDaysOfWeek, J as getMonthAndYear, K as getDaysOfMonth, L as getHourCycle, M as getLocalizedTime, N as getLocalizedDateTime, O as formatValue, P as clampDate, Q as parseAmPm, R as calculateHourFromAMPM } from './data-ae11fd43.js';
13
13
  import { c as createLockController } from './lock-controller-316928be.js';
14
- import { d as createDelegateController, e as createTriggerController, B as BACKDROP, i as isCancel, j as prepareOverlay, k as setOverlayId, f as present, g as dismiss, h as eventMethod, s as safeCall } from './overlays-9c75ec54.js';
14
+ import { d as createDelegateController, e as createTriggerController, B as BACKDROP, i as isCancel, j as prepareOverlay, k as setOverlayId, f as present, g as dismiss, h as eventMethod, s as safeCall } from './overlays-ae10d43d.js';
15
15
  import { c as createAnimation } from './animation-eab5a4ca.js';
16
16
  import { b as hapticSelectionChanged, h as hapticSelectionEnd, a as hapticSelectionStart } from './haptic-ac164e4c.js';
17
17
  import './index-a5d50daf.js';
@@ -25,6 +25,8 @@ const Input = class {
25
25
  this.ionBlur = createEvent(this, "ionBlur", 7);
26
26
  this.ionFocus = createEvent(this, "ionFocus", 7);
27
27
  this.inputId = `ion-input-${inputIds++}`;
28
+ this.helperTextId = `${this.inputId}-helper-text`;
29
+ this.errorTextId = `${this.inputId}-error-text`;
28
30
  this.inheritedAttributes = {};
29
31
  this.isComposing = false;
30
32
  /**
@@ -297,8 +299,21 @@ const Input = class {
297
299
  * Renders the helper text or error text values
298
300
  */
299
301
  renderHintText() {
300
- const { helperText, errorText } = this;
301
- return [h("div", { class: "helper-text" }, helperText), h("div", { class: "error-text" }, errorText)];
302
+ const { helperText, errorText, helperTextId, errorTextId } = this;
303
+ return [
304
+ h("div", { id: helperTextId, class: "helper-text" }, helperText),
305
+ h("div", { id: errorTextId, class: "error-text" }, errorText),
306
+ ];
307
+ }
308
+ getHintTextID() {
309
+ const { el, helperText, errorText, helperTextId, errorTextId } = this;
310
+ if (el.classList.contains('ion-touched') && el.classList.contains('ion-invalid') && errorText) {
311
+ return errorTextId;
312
+ }
313
+ if (helperText) {
314
+ return helperTextId;
315
+ }
316
+ return undefined;
302
317
  }
303
318
  renderCounter() {
304
319
  const { counter, maxlength, counterFormatter, value } = this;
@@ -405,7 +420,7 @@ const Input = class {
405
420
  * TODO(FW-5592): Remove hasStartEndSlots condition
406
421
  */
407
422
  const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || hasFocus || hasStartEndSlots));
408
- return (h(Host, { key: '907ce98a82b5cfae5a08504cd79e00a2330b7444', class: createColorClasses(this.color, {
423
+ return (h(Host, { key: 'cdde9963d71685e6a4f3f3b3bc52e75d022435cb', class: createColorClasses(this.color, {
409
424
  [mode]: true,
410
425
  'has-value': hasValue,
411
426
  'has-focus': hasFocus,
@@ -416,7 +431,7 @@ const Input = class {
416
431
  'in-item': inItem,
417
432
  'in-item-color': hostContext('ion-item.ion-color', this.el),
418
433
  'input-disabled': disabled,
419
- }) }, h("label", { key: '59d5bb45d2a5b828bba0ed8687a632a551e2f4d8', class: "input-wrapper", htmlFor: inputId }, this.renderLabelContainer(), h("div", { key: 'f93f129d08246d0e9a601c100d718534d6403853', class: "native-wrapper" }, h("slot", { key: '54eeb1a6bace662b7eb0d7e27180ea3d7e3a3729', name: "start" }), h("input", Object.assign({ key: 'b3e0be55bc1a4a539ae3b0fdcf7fc078723cca16', class: "native-input", ref: (input) => (this.nativeInput = input), id: inputId, disabled: disabled, autoCapitalize: this.autocapitalize, autoComplete: this.autocomplete, autoCorrect: this.autocorrect, autoFocus: this.autofocus, enterKeyHint: this.enterkeyhint, inputMode: this.inputmode, min: this.min, max: this.max, minLength: this.minlength, maxLength: this.maxlength, multiple: this.multiple, name: this.name, pattern: this.pattern, placeholder: this.placeholder || '', readOnly: readonly, required: this.required, spellcheck: this.spellcheck, step: this.step, type: this.type, value: value, onInput: this.onInput, onChange: this.onChange, onBlur: this.onBlur, onFocus: this.onFocus, onKeyDown: this.onKeydown, onCompositionstart: this.onCompositionStart, onCompositionend: this.onCompositionEnd }, this.inheritedAttributes)), this.clearInput && !readonly && !disabled && (h("button", { key: '5f6373504a6d0d074bfbf875c794d45ea2748175', "aria-label": "reset", type: "button", class: "input-clear-icon", onPointerDown: (ev) => {
434
+ }) }, h("label", { key: '4412791c93405f20e50e50363879265180b6078f', class: "input-wrapper", htmlFor: inputId }, this.renderLabelContainer(), h("div", { key: '5c71c43ef3eeb44dde76ed64ce10763834c8fbc7', class: "native-wrapper" }, h("slot", { key: '1d86b58dc299a4208dd02ccdc9ceaea7576698c3', name: "start" }), h("input", Object.assign({ key: '7fc932174485f7d09e6a797dfd49ea11fbad71b6', class: "native-input", ref: (input) => (this.nativeInput = input), id: inputId, disabled: disabled, autoCapitalize: this.autocapitalize, autoComplete: this.autocomplete, autoCorrect: this.autocorrect, autoFocus: this.autofocus, enterKeyHint: this.enterkeyhint, inputMode: this.inputmode, min: this.min, max: this.max, minLength: this.minlength, maxLength: this.maxlength, multiple: this.multiple, name: this.name, pattern: this.pattern, placeholder: this.placeholder || '', readOnly: readonly, required: this.required, spellcheck: this.spellcheck, step: this.step, type: this.type, value: value, onInput: this.onInput, onChange: this.onChange, onBlur: this.onBlur, onFocus: this.onFocus, onKeyDown: this.onKeydown, onCompositionstart: this.onCompositionStart, onCompositionend: this.onCompositionEnd, "aria-describedby": this.getHintTextID(), "aria-invalid": this.getHintTextID() === this.errorTextId }, this.inheritedAttributes)), this.clearInput && !readonly && !disabled && (h("button", { key: '46de455e4e308b8d7640b04778f7c7559b4124c6', "aria-label": "reset", type: "button", class: "input-clear-icon", onPointerDown: (ev) => {
420
435
  /**
421
436
  * This prevents mobile browsers from
422
437
  * blurring the input when the clear
@@ -431,7 +446,7 @@ const Input = class {
431
446
  * for screen readers as it means users would be unable to swipe past the clear button.
432
447
  */
433
448
  ev.stopPropagation();
434
- }, onClick: this.clearTextInput }, h("ion-icon", { key: '230d77973aa83458ceb32bf52e3abe9bc322cfe6', "aria-hidden": "true", icon: clearIconData }))), h("slot", { key: '9d69ac6e8a3c4b2b303dba2478f82695d5755ed2', name: "end" })), shouldRenderHighlight && h("div", { key: 'ac61f16237ce731e0745ab72d0fc3f066252464a', class: "input-highlight" })), this.renderBottomContent()));
449
+ }, onClick: this.clearTextInput }, h("ion-icon", { key: '375e860a20e1807ce0db0e1934a0650fe9929966', "aria-hidden": "true", icon: clearIconData }))), h("slot", { key: '859d47a1b88aa8377479e5d11e52a6a1c1c30e7e', name: "end" })), shouldRenderHighlight && h("div", { key: 'd2d4286b348107e33247b5c0afda0f8bd697ecee', class: "input-highlight" })), this.renderBottomContent()));
435
450
  }
436
451
  get el() { return getElement(this); }
437
452
  static get watchers() { return {
@@ -5,7 +5,7 @@ import { r as registerInstance, d as createEvent, h, f as Host, i as getElement
5
5
  import { E as ENABLE_HTML_CONTENT_DEFAULT, a as sanitizeDOMString } from './config-49c88215.js';
6
6
  import { r as raf } from './helpers-da915de8.js';
7
7
  import { c as createLockController } from './lock-controller-316928be.js';
8
- import { d as createDelegateController, e as createTriggerController, B as BACKDROP, j as prepareOverlay, k as setOverlayId, f as present, g as dismiss, h as eventMethod } from './overlays-9c75ec54.js';
8
+ import { d as createDelegateController, e as createTriggerController, B as BACKDROP, j as prepareOverlay, k as setOverlayId, f as present, g as dismiss, h as eventMethod } from './overlays-ae10d43d.js';
9
9
  import { g as getClassMap } from './theme-01f3f29c.js';
10
10
  import { c as config, b as getIonMode } from './ionic-global-c81d82ab.js';
11
11
  import { c as createAnimation } from './animation-eab5a4ca.js';
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { r as registerInstance, d as createEvent, h, f as Host, i as getElement } from './index-28849c61.js';
5
5
  import { g as getTimeGivenProgression } from './cubic-bezier-fe2083dc.js';
6
- import { o as getPresentedOverlay, n as focusFirstDescendant, q as focusLastDescendant } from './overlays-9c75ec54.js';
6
+ import { o as getPresentedOverlay, n as focusFirstDescendant, q as focusLastDescendant } from './overlays-ae10d43d.js';
7
7
  import { G as GESTURE_CONTROLLER } from './gesture-controller-314a54f6.js';
8
8
  import { shouldUseCloseWatcher } from './hardware-back-button-06ef3c3e.js';
9
9
  import { n as isEndSide, i as inheritAriaAttributes, m as assert, j as clamp } from './helpers-da915de8.js';
@@ -8,7 +8,7 @@ import { g as getElementRoot, j as clamp, r as raf, h as inheritAttributes, k as
8
8
  import { c as createLockController } from './lock-controller-316928be.js';
9
9
  import { p as printIonWarning } from './index-9b0d46f4.js';
10
10
  import { g as getCapacitor } from './capacitor-59395cbd.js';
11
- import { G as GESTURE, O as OVERLAY_GESTURE_PRIORITY, F as FOCUS_TRAP_DISABLE_CLASS, e as createTriggerController, B as BACKDROP, j as prepareOverlay, k as setOverlayId, f as present, g as dismiss, h as eventMethod } from './overlays-9c75ec54.js';
11
+ import { G as GESTURE, O as OVERLAY_GESTURE_PRIORITY, F as FOCUS_TRAP_DISABLE_CLASS, e as createTriggerController, B as BACKDROP, j as prepareOverlay, k as setOverlayId, f as present, g as dismiss, h as eventMethod } from './overlays-ae10d43d.js';
12
12
  import { g as getClassMap } from './theme-01f3f29c.js';
13
13
  import { e as deepReady, w as waitForMount } from './index-3ad7f18b.js';
14
14
  import { b as getIonMode, c as config } from './ionic-global-c81d82ab.js';
@@ -2,7 +2,7 @@
2
2
  * (C) Ionic http://ionicframework.com - MIT License
3
3
  */
4
4
  import { r as registerInstance, d as createEvent, h, f as Host, i as getElement } from './index-28849c61.js';
5
- import { B as BACKDROP, j as prepareOverlay, k as setOverlayId, f as present, n as focusFirstDescendant, g as dismiss, h as eventMethod, F as FOCUS_TRAP_DISABLE_CLASS } from './overlays-9c75ec54.js';
5
+ import { B as BACKDROP, j as prepareOverlay, k as setOverlayId, f as present, n as focusFirstDescendant, g as dismiss, h as eventMethod, F as FOCUS_TRAP_DISABLE_CLASS } from './overlays-ae10d43d.js';
6
6
  import { C as CoreDelegate, a as attachComponent, d as detachComponent } from './framework-delegate-63d1a679.js';
7
7
  import { r as raf, g as getElementRoot, a as addEventListener, k as hasLazyBuild } from './helpers-da915de8.js';
8
8
  import { c as createLockController } from './lock-controller-316928be.js';
@@ -5,7 +5,7 @@ import { r as registerInstance, d as createEvent, h, f as Host, i as getElement,
5
5
  import { c as createNotchController } from './notch-controller-55b09e11.js';
6
6
  import { i as isOptionSelected, c as compareOptions } from './compare-with-utils-a96ff2ea.js';
7
7
  import { h as inheritAttributes, f as focusVisibleElement, d as renderHiddenInput } from './helpers-da915de8.js';
8
- import { c as popoverController, b as actionSheetController, a as alertController, s as safeCall } from './overlays-9c75ec54.js';
8
+ import { c as popoverController, b as actionSheetController, a as alertController, s as safeCall } from './overlays-ae10d43d.js';
9
9
  import { i as isRTL } from './dir-babeabeb.js';
10
10
  import { h as hostContext, c as createColorClasses, g as getClassMap } from './theme-01f3f29c.js';
11
11
  import { w as watchForOptions } from './watch-options-c2911ace.js';
@@ -24,6 +24,8 @@ const Textarea = class {
24
24
  this.ionBlur = createEvent(this, "ionBlur", 7);
25
25
  this.ionFocus = createEvent(this, "ionFocus", 7);
26
26
  this.inputId = `ion-textarea-${textareaIds++}`;
27
+ this.helperTextId = `${this.inputId}-helper-text`;
28
+ this.errorTextId = `${this.inputId}-error-text`;
27
29
  /**
28
30
  * `true` if the textarea was cleared as a result of the user typing
29
31
  * with `clearOnEdit` enabled.
@@ -311,8 +313,21 @@ const Textarea = class {
311
313
  * Renders the helper text or error text values
312
314
  */
313
315
  renderHintText() {
314
- const { helperText, errorText } = this;
315
- return [h("div", { class: "helper-text" }, helperText), h("div", { class: "error-text" }, errorText)];
316
+ const { helperText, errorText, helperTextId, errorTextId } = this;
317
+ return [
318
+ h("div", { id: helperTextId, class: "helper-text" }, helperText),
319
+ h("div", { id: errorTextId, class: "error-text" }, errorText),
320
+ ];
321
+ }
322
+ getHintTextID() {
323
+ const { el, helperText, errorText, helperTextId, errorTextId } = this;
324
+ if (el.classList.contains('ion-touched') && el.classList.contains('ion-invalid') && errorText) {
325
+ return errorTextId;
326
+ }
327
+ if (helperText) {
328
+ return helperTextId;
329
+ }
330
+ return undefined;
316
331
  }
317
332
  renderCounter() {
318
333
  const { counter, maxlength, counterFormatter, value } = this;
@@ -365,7 +380,7 @@ const Textarea = class {
365
380
  * TODO(FW-5592): Remove hasStartEndSlots condition
366
381
  */
367
382
  const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || hasFocus || hasStartEndSlots));
368
- return (h(Host, { key: '37595a18d77dea1a337ac1c672e5f08a4128111d', class: createColorClasses(this.color, {
383
+ return (h(Host, { key: 'e8a5b5727c6a018bbd6f5507b690bc5f0959e352', class: createColorClasses(this.color, {
369
384
  [mode]: true,
370
385
  'has-value': hasValue,
371
386
  'has-focus': hasFocus,
@@ -374,7 +389,7 @@ const Textarea = class {
374
389
  [`textarea-shape-${shape}`]: shape !== undefined,
375
390
  [`textarea-label-placement-${labelPlacement}`]: true,
376
391
  'textarea-disabled': disabled,
377
- }) }, h("label", { key: '67342758743e5a40448a32ff695876d39778621f', class: "textarea-wrapper", htmlFor: inputId }, this.renderLabelContainer(), h("div", { key: 'a994be8264bf5652811cf816d79a04178954e83f', class: "textarea-wrapper-inner" }, h("div", { key: 'e09c93ebcd5b3d227d51e682ca23dfc7fd7027ad', class: "start-slot-wrapper" }, h("slot", { key: 'd39758f21f19ae70aea21e9a9a7b7c20991fe593', name: "start" })), h("div", { key: '6a4e10e53de4bb235ee30def4c9ae5bdee888816', class: "native-wrapper", ref: (el) => (this.textareaWrapper = el) }, h("textarea", Object.assign({ key: '9e254e551f124d972e9bc6b09ef0f2bb55890be5', class: "native-textarea", ref: (el) => (this.nativeInput = el), id: inputId, disabled: disabled, autoCapitalize: this.autocapitalize, autoFocus: this.autofocus, enterKeyHint: this.enterkeyhint, inputMode: this.inputmode, minLength: this.minlength, maxLength: this.maxlength, name: this.name, placeholder: this.placeholder || '', readOnly: this.readonly, required: this.required, spellcheck: this.spellcheck, cols: this.cols, rows: this.rows, wrap: this.wrap, onInput: this.onInput, onChange: this.onChange, onBlur: this.onBlur, onFocus: this.onFocus, onKeyDown: this.onKeyDown }, this.inheritedAttributes), value)), h("div", { key: 'a66aa2d2bc4778a0bec56a8b9ec9052a832eb3b2', class: "end-slot-wrapper" }, h("slot", { key: '8e6a90b4475de32e23afc593da4108610dcca663', name: "end" }))), shouldRenderHighlight && h("div", { key: '6da03205a8daff45581b20f0af3938634a9d5f8c', class: "textarea-highlight" })), this.renderBottomContent()));
392
+ }) }, h("label", { key: '48e889571e2d3e7e150b038e4b4b15862b418288', class: "textarea-wrapper", htmlFor: inputId }, this.renderLabelContainer(), h("div", { key: '6c6c7872ae4d351d8b8d772ad18ce3ba7a0e9a87', class: "textarea-wrapper-inner" }, h("div", { key: '03aef5dfa59af0fa78a3e5c92e0ed72396717d72', class: "start-slot-wrapper" }, h("slot", { key: '39aee9faebb0f1d10de5a5817fd9d9771b074b96', name: "start" })), h("div", { key: '738e8ff603f4c9b9083b3139db861f4b7ec20f79', class: "native-wrapper", ref: (el) => (this.textareaWrapper = el) }, h("textarea", Object.assign({ key: '7763fb4f8ffe94635167331c70d21d661544c4f8', class: "native-textarea", ref: (el) => (this.nativeInput = el), id: inputId, disabled: disabled, autoCapitalize: this.autocapitalize, autoFocus: this.autofocus, enterKeyHint: this.enterkeyhint, inputMode: this.inputmode, minLength: this.minlength, maxLength: this.maxlength, name: this.name, placeholder: this.placeholder || '', readOnly: this.readonly, required: this.required, spellcheck: this.spellcheck, cols: this.cols, rows: this.rows, wrap: this.wrap, onInput: this.onInput, onChange: this.onChange, onBlur: this.onBlur, onFocus: this.onFocus, onKeyDown: this.onKeyDown, "aria-describedby": this.getHintTextID(), "aria-invalid": this.getHintTextID() === this.errorTextId }, this.inheritedAttributes), value)), h("div", { key: 'b3af9ec0982c6dbd381afaa02df153d7e90471be', class: "end-slot-wrapper" }, h("slot", { key: '60f99bcd49a5ec2e1fa6e3e77809aefeb9d2d0d6', name: "end" }))), shouldRenderHighlight && h("div", { key: '6a7f45639ba027f4da573adae53f1197a6dec383', class: "textarea-highlight" })), this.renderBottomContent()));
378
393
  }
379
394
  get el() { return getElement(this); }
380
395
  static get watchers() { return {
@@ -6,7 +6,7 @@ import { E as ENABLE_HTML_CONTENT_DEFAULT, a as sanitizeDOMString } from './conf
6
6
  import { g as getElementRoot, r as raf } from './helpers-da915de8.js';
7
7
  import { c as createLockController } from './lock-controller-316928be.js';
8
8
  import { p as printIonWarning } from './index-9b0d46f4.js';
9
- import { O as OVERLAY_GESTURE_PRIORITY, d as createDelegateController, e as createTriggerController, i as isCancel, j as prepareOverlay, k as setOverlayId, f as present, g as dismiss, h as eventMethod, s as safeCall, G as GESTURE } from './overlays-9c75ec54.js';
9
+ import { O as OVERLAY_GESTURE_PRIORITY, d as createDelegateController, e as createTriggerController, i as isCancel, j as prepareOverlay, k as setOverlayId, f as present, g as dismiss, h as eventMethod, s as safeCall, G as GESTURE } from './overlays-ae10d43d.js';
10
10
  import { c as createColorClasses, g as getClassMap } from './theme-01f3f29c.js';
11
11
  import { c as config, b as getIonMode } from './ionic-global-c81d82ab.js';
12
12
  import { c as createAnimation } from './animation-eab5a4ca.js';
@@ -500,9 +500,19 @@ const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation, opts)
500
500
  if (overlay.presented) {
501
501
  return;
502
502
  }
503
- setRootAriaHidden(true);
503
+ /**
504
+ * Due to accessibility guidelines, toasts do not have
505
+ * focus traps.
506
+ *
507
+ * All other overlays should have focus traps to prevent
508
+ * the keyboard focus from leaving the overlay.
509
+ */
510
+ if (overlay.el.tagName !== 'ION-TOAST') {
511
+ setRootAriaHidden(true);
512
+ }
504
513
  document.body.classList.add(BACKDROP_NO_SCROLL);
505
- hideOverlaysFromScreenReaders(overlay.el);
514
+ hideUnderlyingOverlaysFromScreenReaders(overlay.el);
515
+ hideAnimatingOverlayFromScreenReaders(overlay.el);
506
516
  overlay.presented = true;
507
517
  overlay.willPresent.emit();
508
518
  (_a = overlay.willPresentShorthand) === null || _a === void 0 ? void 0 : _a.emit();
@@ -542,6 +552,11 @@ const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation, opts)
542
552
  * it would still have aria-hidden on being presented again.
543
553
  * Removing it here ensures the overlay is visible to screen
544
554
  * readers.
555
+ *
556
+ * If this overlay was being presented, then it was hidden
557
+ * from screen readers during the animation. Now that the
558
+ * animation is complete, we can reveal the overlay to
559
+ * screen readers.
545
560
  */
546
561
  overlay.el.removeAttribute('aria-hidden');
547
562
  };
@@ -599,17 +614,35 @@ const dismiss = async (overlay, data, role, name, iosLeaveAnimation, mdLeaveAnim
599
614
  if (!overlay.presented) {
600
615
  return false;
601
616
  }
602
- const lastOverlay = doc !== undefined && getPresentedOverlays(doc).length === 1;
603
617
  /**
604
- * If this is the last visible overlay then
605
- * we want to re-add the root to the accessibility tree.
618
+ * For accessibility, toasts lack focus traps and don’t receive
619
+ * `aria-hidden` on the root element when presented.
620
+ *
621
+ * All other overlays use focus traps to keep keyboard focus
622
+ * within the overlay, setting `aria-hidden` on the root element
623
+ * to enhance accessibility.
624
+ *
625
+ * Therefore, we must remove `aria-hidden` from the root element
626
+ * when the last non-toast overlay is dismissed.
606
627
  */
607
- if (lastOverlay) {
628
+ const overlaysNotToast = doc !== undefined ? getPresentedOverlays(doc).filter((o) => o.tagName !== 'ION-TOAST') : [];
629
+ const lastOverlayNotToast = overlaysNotToast.length === 1 && overlaysNotToast[0].id === overlay.el.id;
630
+ /**
631
+ * If this is the last visible overlay that is not a toast
632
+ * then we want to re-add the root to the accessibility tree.
633
+ */
634
+ if (lastOverlayNotToast) {
608
635
  setRootAriaHidden(false);
609
636
  document.body.classList.remove(BACKDROP_NO_SCROLL);
610
637
  }
611
638
  overlay.presented = false;
612
639
  try {
640
+ /**
641
+ * There is no need to show the overlay to screen readers during
642
+ * the dismiss animation. This is because the overlay will be removed
643
+ * from the DOM after the animation is complete.
644
+ */
645
+ hideAnimatingOverlayFromScreenReaders(overlay.el);
613
646
  // Overlay contents should not be clickable during dismiss
614
647
  overlay.el.style.setProperty('pointer-events', 'none');
615
648
  overlay.willDismiss.emit({ data, role });
@@ -844,6 +877,28 @@ const createTriggerController = () => {
844
877
  removeClickListener,
845
878
  };
846
879
  };
880
+ /**
881
+ * The overlay that is being animated also needs to hide from screen
882
+ * readers during its animation. This ensures that assistive technologies
883
+ * like TalkBack do not announce or interact with the content until the
884
+ * animation is complete, avoiding confusion for users.
885
+ *
886
+ * If the overlay is being presented, it prevents focus rings from appearing
887
+ * in incorrect positions due to the transition (specifically `transform`
888
+ * styles), ensuring that when aria-hidden is removed, the focus rings are
889
+ * correctly displayed in the final location of the elements.
890
+ *
891
+ * @param overlay - The overlay that is being animated.
892
+ */
893
+ const hideAnimatingOverlayFromScreenReaders = (overlay) => {
894
+ if (doc === undefined)
895
+ return;
896
+ /**
897
+ * Once the animation is complete, this attribute will be removed.
898
+ * This is done at the end of the `present` method.
899
+ */
900
+ overlay.setAttribute('aria-hidden', 'true');
901
+ };
847
902
  /**
848
903
  * Ensure that underlying overlays have aria-hidden if necessary so that screen readers
849
904
  * cannot move focus to these elements. Note that we cannot rely on focus/focusin/focusout
@@ -854,7 +909,7 @@ const createTriggerController = () => {
854
909
  * @param newTopMostOverlay - The overlay that is being presented. Since the overlay has not been
855
910
  * fully presented yet at the time this function is called it will not be included in the getPresentedOverlays result.
856
911
  */
857
- const hideOverlaysFromScreenReaders = (newTopMostOverlay) => {
912
+ const hideUnderlyingOverlaysFromScreenReaders = (newTopMostOverlay) => {
858
913
  var _a;
859
914
  if (doc === undefined)
860
915
  return;
@@ -1,4 +1,4 @@
1
1
  /*!
2
2
  * (C) Ionic http://ionicframework.com - MIT License
3
3
  */
4
- export{c as createAnimation}from"./animation-eab5a4ca.js";export{a as LIFECYCLE_DID_ENTER,c as LIFECYCLE_DID_LEAVE,L as LIFECYCLE_WILL_ENTER,b as LIFECYCLE_WILL_LEAVE,d as LIFECYCLE_WILL_UNLOAD,g as getIonPageElement}from"./index-3ad7f18b.js";export{iosTransitionAnimation}from"./ios.transition-4ee1a3af.js";export{mdTransitionAnimation}from"./md.transition-5106a0d2.js";export{g as getTimeGivenProgression}from"./cubic-bezier-fe2083dc.js";export{createGesture}from"./index-39782642.js";export{g as getPlatforms,i as initialize,a as isPlatform}from"./ionic-global-c81d82ab.js";export{c as componentOnReady}from"./helpers-da915de8.js";export{I as IonicSafeString,g as getMode,s as setupConfig}from"./config-49c88215.js";export{o as openURL}from"./theme-01f3f29c.js";export{m as menuController}from"./index-fe1782b1.js";export{b as actionSheetController,a as alertController,l as loadingController,m as modalController,p as pickerController,c as popoverController,t as toastController}from"./overlays-9c75ec54.js";import"./index-a5d50daf.js";import"./index-28849c61.js";import"./index-9b0d46f4.js";import"./gesture-controller-314a54f6.js";import"./hardware-back-button-06ef3c3e.js";import"./framework-delegate-63d1a679.js";var IonicSlides=function(e){var o=e.swiper,t=e.extendParams;var s={effect:undefined,direction:"horizontal",initialSlide:0,loop:false,parallax:false,slidesPerView:1,spaceBetween:0,speed:300,slidesPerColumn:1,slidesPerColumnFill:"column",slidesPerGroup:1,centeredSlides:false,slidesOffsetBefore:0,slidesOffsetAfter:0,touchEventsTarget:"container",freeMode:false,freeModeMomentum:true,freeModeMomentumRatio:1,freeModeMomentumBounce:true,freeModeMomentumBounceRatio:1,freeModeMomentumVelocityRatio:1,freeModeSticky:false,freeModeMinimumVelocity:.02,autoHeight:false,setWrapperSize:false,zoom:{maxRatio:3,minRatio:1,toggle:false},touchRatio:1,touchAngle:45,simulateTouch:true,touchStartPreventDefault:false,shortSwipes:true,longSwipes:true,longSwipesRatio:.5,longSwipesMs:300,followFinger:true,threshold:0,touchMoveStopPropagation:true,touchReleaseOnEdges:false,iOSEdgeSwipeDetection:false,iOSEdgeSwipeThreshold:20,resistance:true,resistanceRatio:.85,watchSlidesProgress:false,watchSlidesVisibility:false,preventClicks:true,preventClicksPropagation:true,slideToClickedSlide:false,loopAdditionalSlides:0,noSwiping:true,runCallbacksOnInit:true,coverflowEffect:{rotate:50,stretch:0,depth:100,modifier:1,slideShadows:true},flipEffect:{slideShadows:true,limitRotation:true},cubeEffect:{slideShadows:true,shadow:true,shadowOffset:20,shadowScale:.94},fadeEffect:{crossFade:false},a11y:{prevSlideMessage:"Previous slide",nextSlideMessage:"Next slide",firstSlideMessage:"This is the first slide",lastSlideMessage:"This is the last slide"}};if(o.pagination){s.pagination={type:"bullets",clickable:false,hideOnClick:false}}if(o.scrollbar){s.scrollbar={hide:true}}t(s)};export{IonicSlides};
4
+ export{c as createAnimation}from"./animation-eab5a4ca.js";export{a as LIFECYCLE_DID_ENTER,c as LIFECYCLE_DID_LEAVE,L as LIFECYCLE_WILL_ENTER,b as LIFECYCLE_WILL_LEAVE,d as LIFECYCLE_WILL_UNLOAD,g as getIonPageElement}from"./index-3ad7f18b.js";export{iosTransitionAnimation}from"./ios.transition-4ee1a3af.js";export{mdTransitionAnimation}from"./md.transition-5106a0d2.js";export{g as getTimeGivenProgression}from"./cubic-bezier-fe2083dc.js";export{createGesture}from"./index-39782642.js";export{g as getPlatforms,i as initialize,a as isPlatform}from"./ionic-global-c81d82ab.js";export{c as componentOnReady}from"./helpers-da915de8.js";export{I as IonicSafeString,g as getMode,s as setupConfig}from"./config-49c88215.js";export{o as openURL}from"./theme-01f3f29c.js";export{m as menuController}from"./index-fe1782b1.js";export{b as actionSheetController,a as alertController,l as loadingController,m as modalController,p as pickerController,c as popoverController,t as toastController}from"./overlays-ae10d43d.js";import"./index-a5d50daf.js";import"./index-28849c61.js";import"./index-9b0d46f4.js";import"./gesture-controller-314a54f6.js";import"./hardware-back-button-06ef3c3e.js";import"./framework-delegate-63d1a679.js";var IonicSlides=function(e){var o=e.swiper,t=e.extendParams;var s={effect:undefined,direction:"horizontal",initialSlide:0,loop:false,parallax:false,slidesPerView:1,spaceBetween:0,speed:300,slidesPerColumn:1,slidesPerColumnFill:"column",slidesPerGroup:1,centeredSlides:false,slidesOffsetBefore:0,slidesOffsetAfter:0,touchEventsTarget:"container",freeMode:false,freeModeMomentum:true,freeModeMomentumRatio:1,freeModeMomentumBounce:true,freeModeMomentumBounceRatio:1,freeModeMomentumVelocityRatio:1,freeModeSticky:false,freeModeMinimumVelocity:.02,autoHeight:false,setWrapperSize:false,zoom:{maxRatio:3,minRatio:1,toggle:false},touchRatio:1,touchAngle:45,simulateTouch:true,touchStartPreventDefault:false,shortSwipes:true,longSwipes:true,longSwipesRatio:.5,longSwipesMs:300,followFinger:true,threshold:0,touchMoveStopPropagation:true,touchReleaseOnEdges:false,iOSEdgeSwipeDetection:false,iOSEdgeSwipeThreshold:20,resistance:true,resistanceRatio:.85,watchSlidesProgress:false,watchSlidesVisibility:false,preventClicks:true,preventClicksPropagation:true,slideToClickedSlide:false,loopAdditionalSlides:0,noSwiping:true,runCallbacksOnInit:true,coverflowEffect:{rotate:50,stretch:0,depth:100,modifier:1,slideShadows:true},flipEffect:{slideShadows:true,limitRotation:true},cubeEffect:{slideShadows:true,shadow:true,shadowOffset:20,shadowScale:.94},fadeEffect:{crossFade:false},a11y:{prevSlideMessage:"Previous slide",nextSlideMessage:"Next slide",firstSlideMessage:"This is the first slide",lastSlideMessage:"This is the last slide"}};if(o.pagination){s.pagination={type:"bullets",clickable:false,hideOnClick:false}}if(o.scrollbar){s.scrollbar={hide:true}}t(s)};export{IonicSlides};