@ionic/core 8.3.4-nightly.20241025 → 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 (83) hide show
  1. package/components/ion-input.js +20 -5
  2. package/components/ion-textarea.js +19 -4
  3. package/components/overlays.js +26 -5
  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-99f0578e.js → overlays-ba0f6986.js} +26 -5
  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 +26 -5
  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-d597fdaf.js → overlays-ae10d43d.js} +26 -5
  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-61c3ffe5.system.js → p-04fc24ee.system.js} +1 -1
  50. package/dist/ionic/{p-fcf0c818.entry.js → p-0c7e32d6.entry.js} +1 -1
  51. package/dist/ionic/{p-c7283303.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-27c6b6b7.system.entry.js → p-2031811e.system.entry.js} +1 -1
  55. package/dist/ionic/{p-d4995eda.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-49c0907c.system.entry.js → p-63d65dbc.system.entry.js} +1 -1
  59. package/dist/ionic/{p-f01b6d5d.entry.js → p-6d50faff.entry.js} +1 -1
  60. package/dist/ionic/{p-038ea840.system.js → p-79b12fda.system.js} +1 -1
  61. package/dist/ionic/{p-cdbced33.system.entry.js → p-79e7be3a.system.entry.js} +1 -1
  62. package/dist/ionic/{p-dfac744b.entry.js → p-8640e9cd.entry.js} +1 -1
  63. package/dist/ionic/{p-41bce8cd.entry.js → p-87a4407b.entry.js} +1 -1
  64. package/dist/ionic/{p-d2637ca0.entry.js → p-8ff21f38.entry.js} +1 -1
  65. package/dist/ionic/{p-3f2d6260.system.entry.js → p-921e159f.system.entry.js} +1 -1
  66. package/dist/ionic/{p-2e7be929.entry.js → p-9895e7f3.entry.js} +1 -1
  67. package/dist/ionic/{p-efce3337.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-17c10d59.system.entry.js → p-c3cd6947.system.entry.js} +1 -1
  70. package/dist/ionic/{p-ecadbe91.entry.js → p-c444705a.entry.js} +1 -1
  71. package/dist/ionic/{p-e2dca49f.entry.js → p-d5abc4b3.entry.js} +1 -1
  72. package/dist/ionic/p-dda5c73d.entry.js +4 -0
  73. package/dist/ionic/{p-df4085d5.system.entry.js → p-f0ab13a8.system.entry.js} +1 -1
  74. package/dist/ionic/{p-09b2a941.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 +65 -14
  78. package/hydrate/index.mjs +65 -14
  79. package/package.json +1 -1
  80. package/dist/esm-es5/overlays-d597fdaf.js +0 -4
  81. package/dist/ionic/p-2c4bdd9d.entry.js +0 -4
  82. package/dist/ionic/p-7d1ef246.js +0 -4
  83. package/dist/ionic/p-bfa2e81c.entry.js +0 -4
@@ -25,6 +25,8 @@ const Input = /*@__PURE__*/ proxyCustomElement(class Input extends HTMLElement {
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 = /*@__PURE__*/ proxyCustomElement(class Input extends HTMLElement {
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 = /*@__PURE__*/ proxyCustomElement(class Input extends HTMLElement {
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 = /*@__PURE__*/ proxyCustomElement(class Input extends HTMLElement {
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 = /*@__PURE__*/ proxyCustomElement(class Input extends HTMLElement {
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 this; }
437
452
  static get watchers() { return {
@@ -23,6 +23,8 @@ const Textarea = /*@__PURE__*/ proxyCustomElement(class Textarea extends HTMLEle
23
23
  this.ionBlur = createEvent(this, "ionBlur", 7);
24
24
  this.ionFocus = createEvent(this, "ionFocus", 7);
25
25
  this.inputId = `ion-textarea-${textareaIds++}`;
26
+ this.helperTextId = `${this.inputId}-helper-text`;
27
+ this.errorTextId = `${this.inputId}-error-text`;
26
28
  /**
27
29
  * `true` if the textarea was cleared as a result of the user typing
28
30
  * with `clearOnEdit` enabled.
@@ -310,8 +312,21 @@ const Textarea = /*@__PURE__*/ proxyCustomElement(class Textarea extends HTMLEle
310
312
  * Renders the helper text or error text values
311
313
  */
312
314
  renderHintText() {
313
- const { helperText, errorText } = this;
314
- return [h("div", { class: "helper-text" }, helperText), h("div", { class: "error-text" }, errorText)];
315
+ const { helperText, errorText, helperTextId, errorTextId } = this;
316
+ return [
317
+ h("div", { id: helperTextId, class: "helper-text" }, helperText),
318
+ h("div", { id: errorTextId, class: "error-text" }, errorText),
319
+ ];
320
+ }
321
+ getHintTextID() {
322
+ const { el, helperText, errorText, helperTextId, errorTextId } = this;
323
+ if (el.classList.contains('ion-touched') && el.classList.contains('ion-invalid') && errorText) {
324
+ return errorTextId;
325
+ }
326
+ if (helperText) {
327
+ return helperTextId;
328
+ }
329
+ return undefined;
315
330
  }
316
331
  renderCounter() {
317
332
  const { counter, maxlength, counterFormatter, value } = this;
@@ -364,7 +379,7 @@ const Textarea = /*@__PURE__*/ proxyCustomElement(class Textarea extends HTMLEle
364
379
  * TODO(FW-5592): Remove hasStartEndSlots condition
365
380
  */
366
381
  const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || hasFocus || hasStartEndSlots));
367
- return (h(Host, { key: '37595a18d77dea1a337ac1c672e5f08a4128111d', class: createColorClasses(this.color, {
382
+ return (h(Host, { key: 'e8a5b5727c6a018bbd6f5507b690bc5f0959e352', class: createColorClasses(this.color, {
368
383
  [mode]: true,
369
384
  'has-value': hasValue,
370
385
  'has-focus': hasFocus,
@@ -373,7 +388,7 @@ const Textarea = /*@__PURE__*/ proxyCustomElement(class Textarea extends HTMLEle
373
388
  [`textarea-shape-${shape}`]: shape !== undefined,
374
389
  [`textarea-label-placement-${labelPlacement}`]: true,
375
390
  'textarea-disabled': disabled,
376
- }) }, 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()));
391
+ }) }, 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()));
377
392
  }
378
393
  get el() { return this; }
379
394
  static get watchers() { return {
@@ -500,7 +500,16 @@ 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
514
  hideUnderlyingOverlaysFromScreenReaders(overlay.el);
506
515
  hideAnimatingOverlayFromScreenReaders(overlay.el);
@@ -605,12 +614,24 @@ const dismiss = async (overlay, data, role, name, iosLeaveAnimation, mdLeaveAnim
605
614
  if (!overlay.presented) {
606
615
  return false;
607
616
  }
608
- const lastOverlay = doc !== undefined && getPresentedOverlays(doc).length === 1;
609
617
  /**
610
- * If this is the last visible overlay then
611
- * 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.
627
+ */
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.
612
633
  */
613
- if (lastOverlay) {
634
+ if (lastOverlayNotToast) {
614
635
  setRootAriaHidden(false);
615
636
  document.body.classList.remove(BACKDROP_NO_SCROLL);
616
637
  }
@@ -16,7 +16,7 @@ const helpers = require('./helpers-afaa9001.js');
16
16
  const config = require('./config-4f60b98a.js');
17
17
  const theme = require('./theme-d1c573d2.js');
18
18
  const index$2 = require('./index-9cd00dc3.js');
19
- const overlays = require('./overlays-99f0578e.js');
19
+ const overlays = require('./overlays-ba0f6986.js');
20
20
  require('./index-c8d52405.js');
21
21
  require('./index-73f75efb.js');
22
22
  require('./index-5915f9b3.js');
@@ -9,7 +9,7 @@ const index = require('./index-73f75efb.js');
9
9
  const buttonActive = require('./button-active-3f2f60b4.js');
10
10
  const helpers = require('./helpers-afaa9001.js');
11
11
  const lockController = require('./lock-controller-6585a42a.js');
12
- const overlays = require('./overlays-99f0578e.js');
12
+ const overlays = require('./overlays-ba0f6986.js');
13
13
  const theme = require('./theme-d1c573d2.js');
14
14
  const ionicGlobal = require('./ionic-global-d9a8bb5b.js');
15
15
  const animation = require('./animation-b4fdf128.js');
@@ -10,7 +10,7 @@ const config = require('./config-4f60b98a.js');
10
10
  const buttonActive = require('./button-active-3f2f60b4.js');
11
11
  const helpers = require('./helpers-afaa9001.js');
12
12
  const lockController = require('./lock-controller-6585a42a.js');
13
- const overlays = require('./overlays-99f0578e.js');
13
+ const overlays = require('./overlays-ba0f6986.js');
14
14
  const theme = require('./theme-d1c573d2.js');
15
15
  const ionicGlobal = require('./ionic-global-d9a8bb5b.js');
16
16
  const animation = require('./animation-b4fdf128.js');
@@ -15,7 +15,7 @@ const index$2 = require('./index-073c7cdc.js');
15
15
  const ionicGlobal = require('./ionic-global-d9a8bb5b.js');
16
16
  const data = require('./data-21dc0f81.js');
17
17
  const lockController = require('./lock-controller-6585a42a.js');
18
- const overlays = require('./overlays-99f0578e.js');
18
+ const overlays = require('./overlays-ba0f6986.js');
19
19
  const animation = require('./animation-b4fdf128.js');
20
20
  const haptic = require('./haptic-f6b37aa3.js');
21
21
  require('./index-c8d52405.js');
@@ -29,6 +29,8 @@ const Input = class {
29
29
  this.ionBlur = index.createEvent(this, "ionBlur", 7);
30
30
  this.ionFocus = index.createEvent(this, "ionFocus", 7);
31
31
  this.inputId = `ion-input-${inputIds++}`;
32
+ this.helperTextId = `${this.inputId}-helper-text`;
33
+ this.errorTextId = `${this.inputId}-error-text`;
32
34
  this.inheritedAttributes = {};
33
35
  this.isComposing = false;
34
36
  /**
@@ -301,8 +303,21 @@ const Input = class {
301
303
  * Renders the helper text or error text values
302
304
  */
303
305
  renderHintText() {
304
- const { helperText, errorText } = this;
305
- return [index.h("div", { class: "helper-text" }, helperText), index.h("div", { class: "error-text" }, errorText)];
306
+ const { helperText, errorText, helperTextId, errorTextId } = this;
307
+ return [
308
+ index.h("div", { id: helperTextId, class: "helper-text" }, helperText),
309
+ index.h("div", { id: errorTextId, class: "error-text" }, errorText),
310
+ ];
311
+ }
312
+ getHintTextID() {
313
+ const { el, helperText, errorText, helperTextId, errorTextId } = this;
314
+ if (el.classList.contains('ion-touched') && el.classList.contains('ion-invalid') && errorText) {
315
+ return errorTextId;
316
+ }
317
+ if (helperText) {
318
+ return helperTextId;
319
+ }
320
+ return undefined;
306
321
  }
307
322
  renderCounter() {
308
323
  const { counter, maxlength, counterFormatter, value } = this;
@@ -409,7 +424,7 @@ const Input = class {
409
424
  * TODO(FW-5592): Remove hasStartEndSlots condition
410
425
  */
411
426
  const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || hasFocus || hasStartEndSlots));
412
- return (index.h(index.Host, { key: '907ce98a82b5cfae5a08504cd79e00a2330b7444', class: theme.createColorClasses(this.color, {
427
+ return (index.h(index.Host, { key: 'cdde9963d71685e6a4f3f3b3bc52e75d022435cb', class: theme.createColorClasses(this.color, {
413
428
  [mode]: true,
414
429
  'has-value': hasValue,
415
430
  'has-focus': hasFocus,
@@ -420,7 +435,7 @@ const Input = class {
420
435
  'in-item': inItem,
421
436
  'in-item-color': theme.hostContext('ion-item.ion-color', this.el),
422
437
  'input-disabled': disabled,
423
- }) }, index.h("label", { key: '59d5bb45d2a5b828bba0ed8687a632a551e2f4d8', class: "input-wrapper", htmlFor: inputId }, this.renderLabelContainer(), index.h("div", { key: 'f93f129d08246d0e9a601c100d718534d6403853', class: "native-wrapper" }, index.h("slot", { key: '54eeb1a6bace662b7eb0d7e27180ea3d7e3a3729', name: "start" }), index.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 && (index.h("button", { key: '5f6373504a6d0d074bfbf875c794d45ea2748175', "aria-label": "reset", type: "button", class: "input-clear-icon", onPointerDown: (ev) => {
438
+ }) }, index.h("label", { key: '4412791c93405f20e50e50363879265180b6078f', class: "input-wrapper", htmlFor: inputId }, this.renderLabelContainer(), index.h("div", { key: '5c71c43ef3eeb44dde76ed64ce10763834c8fbc7', class: "native-wrapper" }, index.h("slot", { key: '1d86b58dc299a4208dd02ccdc9ceaea7576698c3', name: "start" }), index.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 && (index.h("button", { key: '46de455e4e308b8d7640b04778f7c7559b4124c6', "aria-label": "reset", type: "button", class: "input-clear-icon", onPointerDown: (ev) => {
424
439
  /**
425
440
  * This prevents mobile browsers from
426
441
  * blurring the input when the clear
@@ -435,7 +450,7 @@ const Input = class {
435
450
  * for screen readers as it means users would be unable to swipe past the clear button.
436
451
  */
437
452
  ev.stopPropagation();
438
- }, onClick: this.clearTextInput }, index.h("ion-icon", { key: '230d77973aa83458ceb32bf52e3abe9bc322cfe6', "aria-hidden": "true", icon: clearIconData }))), index.h("slot", { key: '9d69ac6e8a3c4b2b303dba2478f82695d5755ed2', name: "end" })), shouldRenderHighlight && index.h("div", { key: 'ac61f16237ce731e0745ab72d0fc3f066252464a', class: "input-highlight" })), this.renderBottomContent()));
453
+ }, onClick: this.clearTextInput }, index.h("ion-icon", { key: '375e860a20e1807ce0db0e1934a0650fe9929966', "aria-hidden": "true", icon: clearIconData }))), index.h("slot", { key: '859d47a1b88aa8377479e5d11e52a6a1c1c30e7e', name: "end" })), shouldRenderHighlight && index.h("div", { key: 'd2d4286b348107e33247b5c0afda0f8bd697ecee', class: "input-highlight" })), this.renderBottomContent()));
439
454
  }
440
455
  get el() { return index.getElement(this); }
441
456
  static get watchers() { return {
@@ -9,7 +9,7 @@ const index = require('./index-73f75efb.js');
9
9
  const config = require('./config-4f60b98a.js');
10
10
  const helpers = require('./helpers-afaa9001.js');
11
11
  const lockController = require('./lock-controller-6585a42a.js');
12
- const overlays = require('./overlays-99f0578e.js');
12
+ const overlays = require('./overlays-ba0f6986.js');
13
13
  const theme = require('./theme-d1c573d2.js');
14
14
  const ionicGlobal = require('./ionic-global-d9a8bb5b.js');
15
15
  const animation = require('./animation-b4fdf128.js');
@@ -7,7 +7,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
7
7
 
8
8
  const index = require('./index-73f75efb.js');
9
9
  const cubicBezier = require('./cubic-bezier-f2dccc53.js');
10
- const overlays = require('./overlays-99f0578e.js');
10
+ const overlays = require('./overlays-ba0f6986.js');
11
11
  const gestureController = require('./gesture-controller-9436f482.js');
12
12
  const hardwareBackButton = require('./hardware-back-button-9e8a2c4f.js');
13
13
  const helpers = require('./helpers-afaa9001.js');
@@ -12,7 +12,7 @@ const helpers = require('./helpers-afaa9001.js');
12
12
  const lockController = require('./lock-controller-6585a42a.js');
13
13
  const index$4 = require('./index-5915f9b3.js');
14
14
  const capacitor = require('./capacitor-c04564bf.js');
15
- const overlays = require('./overlays-99f0578e.js');
15
+ const overlays = require('./overlays-ba0f6986.js');
16
16
  const theme = require('./theme-d1c573d2.js');
17
17
  const index$5 = require('./index-f05acd21.js');
18
18
  const ionicGlobal = require('./ionic-global-d9a8bb5b.js');
@@ -6,7 +6,7 @@
6
6
  Object.defineProperty(exports, '__esModule', { value: true });
7
7
 
8
8
  const index = require('./index-73f75efb.js');
9
- const overlays = require('./overlays-99f0578e.js');
9
+ const overlays = require('./overlays-ba0f6986.js');
10
10
  const frameworkDelegate = require('./framework-delegate-55f5683a.js');
11
11
  const helpers = require('./helpers-afaa9001.js');
12
12
  const lockController = require('./lock-controller-6585a42a.js');
@@ -9,7 +9,7 @@ const index = require('./index-73f75efb.js');
9
9
  const notchController = require('./notch-controller-d69150f5.js');
10
10
  const compareWithUtils = require('./compare-with-utils-df1001d7.js');
11
11
  const helpers = require('./helpers-afaa9001.js');
12
- const overlays = require('./overlays-99f0578e.js');
12
+ const overlays = require('./overlays-ba0f6986.js');
13
13
  const dir = require('./dir-94c21456.js');
14
14
  const theme = require('./theme-d1c573d2.js');
15
15
  const watchOptions = require('./watch-options-f5f3e158.js');
@@ -28,6 +28,8 @@ const Textarea = class {
28
28
  this.ionBlur = index.createEvent(this, "ionBlur", 7);
29
29
  this.ionFocus = index.createEvent(this, "ionFocus", 7);
30
30
  this.inputId = `ion-textarea-${textareaIds++}`;
31
+ this.helperTextId = `${this.inputId}-helper-text`;
32
+ this.errorTextId = `${this.inputId}-error-text`;
31
33
  /**
32
34
  * `true` if the textarea was cleared as a result of the user typing
33
35
  * with `clearOnEdit` enabled.
@@ -315,8 +317,21 @@ const Textarea = class {
315
317
  * Renders the helper text or error text values
316
318
  */
317
319
  renderHintText() {
318
- const { helperText, errorText } = this;
319
- return [index.h("div", { class: "helper-text" }, helperText), index.h("div", { class: "error-text" }, errorText)];
320
+ const { helperText, errorText, helperTextId, errorTextId } = this;
321
+ return [
322
+ index.h("div", { id: helperTextId, class: "helper-text" }, helperText),
323
+ index.h("div", { id: errorTextId, class: "error-text" }, errorText),
324
+ ];
325
+ }
326
+ getHintTextID() {
327
+ const { el, helperText, errorText, helperTextId, errorTextId } = this;
328
+ if (el.classList.contains('ion-touched') && el.classList.contains('ion-invalid') && errorText) {
329
+ return errorTextId;
330
+ }
331
+ if (helperText) {
332
+ return helperTextId;
333
+ }
334
+ return undefined;
320
335
  }
321
336
  renderCounter() {
322
337
  const { counter, maxlength, counterFormatter, value } = this;
@@ -369,7 +384,7 @@ const Textarea = class {
369
384
  * TODO(FW-5592): Remove hasStartEndSlots condition
370
385
  */
371
386
  const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || hasFocus || hasStartEndSlots));
372
- return (index.h(index.Host, { key: '37595a18d77dea1a337ac1c672e5f08a4128111d', class: theme.createColorClasses(this.color, {
387
+ return (index.h(index.Host, { key: 'e8a5b5727c6a018bbd6f5507b690bc5f0959e352', class: theme.createColorClasses(this.color, {
373
388
  [mode]: true,
374
389
  'has-value': hasValue,
375
390
  'has-focus': hasFocus,
@@ -378,7 +393,7 @@ const Textarea = class {
378
393
  [`textarea-shape-${shape}`]: shape !== undefined,
379
394
  [`textarea-label-placement-${labelPlacement}`]: true,
380
395
  'textarea-disabled': disabled,
381
- }) }, index.h("label", { key: '67342758743e5a40448a32ff695876d39778621f', class: "textarea-wrapper", htmlFor: inputId }, this.renderLabelContainer(), index.h("div", { key: 'a994be8264bf5652811cf816d79a04178954e83f', class: "textarea-wrapper-inner" }, index.h("div", { key: 'e09c93ebcd5b3d227d51e682ca23dfc7fd7027ad', class: "start-slot-wrapper" }, index.h("slot", { key: 'd39758f21f19ae70aea21e9a9a7b7c20991fe593', name: "start" })), index.h("div", { key: '6a4e10e53de4bb235ee30def4c9ae5bdee888816', class: "native-wrapper", ref: (el) => (this.textareaWrapper = el) }, index.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)), index.h("div", { key: 'a66aa2d2bc4778a0bec56a8b9ec9052a832eb3b2', class: "end-slot-wrapper" }, index.h("slot", { key: '8e6a90b4475de32e23afc593da4108610dcca663', name: "end" }))), shouldRenderHighlight && index.h("div", { key: '6da03205a8daff45581b20f0af3938634a9d5f8c', class: "textarea-highlight" })), this.renderBottomContent()));
396
+ }) }, index.h("label", { key: '48e889571e2d3e7e150b038e4b4b15862b418288', class: "textarea-wrapper", htmlFor: inputId }, this.renderLabelContainer(), index.h("div", { key: '6c6c7872ae4d351d8b8d772ad18ce3ba7a0e9a87', class: "textarea-wrapper-inner" }, index.h("div", { key: '03aef5dfa59af0fa78a3e5c92e0ed72396717d72', class: "start-slot-wrapper" }, index.h("slot", { key: '39aee9faebb0f1d10de5a5817fd9d9771b074b96', name: "start" })), index.h("div", { key: '738e8ff603f4c9b9083b3139db861f4b7ec20f79', class: "native-wrapper", ref: (el) => (this.textareaWrapper = el) }, index.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)), index.h("div", { key: 'b3af9ec0982c6dbd381afaa02df153d7e90471be', class: "end-slot-wrapper" }, index.h("slot", { key: '60f99bcd49a5ec2e1fa6e3e77809aefeb9d2d0d6', name: "end" }))), shouldRenderHighlight && index.h("div", { key: '6a7f45639ba027f4da573adae53f1197a6dec383', class: "textarea-highlight" })), this.renderBottomContent()));
382
397
  }
383
398
  get el() { return index.getElement(this); }
384
399
  static get watchers() { return {
@@ -10,7 +10,7 @@ const config = require('./config-4f60b98a.js');
10
10
  const helpers = require('./helpers-afaa9001.js');
11
11
  const lockController = require('./lock-controller-6585a42a.js');
12
12
  const index$1 = require('./index-5915f9b3.js');
13
- const overlays = require('./overlays-99f0578e.js');
13
+ const overlays = require('./overlays-ba0f6986.js');
14
14
  const theme = require('./theme-d1c573d2.js');
15
15
  const ionicGlobal = require('./ionic-global-d9a8bb5b.js');
16
16
  const animation = require('./animation-b4fdf128.js');
@@ -502,7 +502,16 @@ const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation, opts)
502
502
  if (overlay.presented) {
503
503
  return;
504
504
  }
505
- setRootAriaHidden(true);
505
+ /**
506
+ * Due to accessibility guidelines, toasts do not have
507
+ * focus traps.
508
+ *
509
+ * All other overlays should have focus traps to prevent
510
+ * the keyboard focus from leaving the overlay.
511
+ */
512
+ if (overlay.el.tagName !== 'ION-TOAST') {
513
+ setRootAriaHidden(true);
514
+ }
506
515
  document.body.classList.add(gestureController.BACKDROP_NO_SCROLL);
507
516
  hideUnderlyingOverlaysFromScreenReaders(overlay.el);
508
517
  hideAnimatingOverlayFromScreenReaders(overlay.el);
@@ -607,12 +616,24 @@ const dismiss = async (overlay, data, role, name, iosLeaveAnimation, mdLeaveAnim
607
616
  if (!overlay.presented) {
608
617
  return false;
609
618
  }
610
- const lastOverlay = index.doc !== undefined && getPresentedOverlays(index.doc).length === 1;
611
619
  /**
612
- * If this is the last visible overlay then
613
- * we want to re-add the root to the accessibility tree.
620
+ * For accessibility, toasts lack focus traps and don’t receive
621
+ * `aria-hidden` on the root element when presented.
622
+ *
623
+ * All other overlays use focus traps to keep keyboard focus
624
+ * within the overlay, setting `aria-hidden` on the root element
625
+ * to enhance accessibility.
626
+ *
627
+ * Therefore, we must remove `aria-hidden` from the root element
628
+ * when the last non-toast overlay is dismissed.
629
+ */
630
+ const overlaysNotToast = index.doc !== undefined ? getPresentedOverlays(index.doc).filter((o) => o.tagName !== 'ION-TOAST') : [];
631
+ const lastOverlayNotToast = overlaysNotToast.length === 1 && overlaysNotToast[0].id === overlay.el.id;
632
+ /**
633
+ * If this is the last visible overlay that is not a toast
634
+ * then we want to re-add the root to the accessibility tree.
614
635
  */
615
- if (lastOverlay) {
636
+ if (lastOverlayNotToast) {
616
637
  setRootAriaHidden(false);
617
638
  document.body.classList.remove(gestureController.BACKDROP_NO_SCROLL);
618
639
  }
@@ -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,7 +427,16 @@ 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
441
  hideUnderlyingOverlaysFromScreenReaders(overlay.el);
433
442
  hideAnimatingOverlayFromScreenReaders(overlay.el);
@@ -532,12 +541,24 @@ export const dismiss = async (overlay, data, role, name, iosLeaveAnimation, mdLe
532
541
  if (!overlay.presented) {
533
542
  return false;
534
543
  }
535
- const lastOverlay = doc !== undefined && getPresentedOverlays(doc).length === 1;
536
544
  /**
537
- * If this is the last visible overlay then
538
- * 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.
554
+ */
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.
539
560
  */
540
- if (lastOverlay) {
561
+ if (lastOverlayNotToast) {
541
562
  setRootAriaHidden(false);
542
563
  document.body.classList.remove(BACKDROP_NO_SCROLL);
543
564
  }
package/dist/docs.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2024-10-25T06:09:16",
2
+ "timestamp": "2024-10-28T06:10:05",
3
3
  "compiler": {
4
4
  "name": "@stencil/core",
5
5
  "version": "4.20.0",