@ionic/core 8.7.7-nightly.20251014 → 8.7.7

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 (78) hide show
  1. package/components/button.js +3 -7
  2. package/components/header.js +42 -4
  3. package/components/index2.js +74 -3
  4. package/components/ion-input.js +6 -14
  5. package/components/ion-select.js +58 -10
  6. package/components/ion-textarea.js +5 -13
  7. package/components/{notch-controller.js → validity.js} +14 -1
  8. package/dist/cjs/{index-CD5Rjp23.js → index-094mMFB-.js} +76 -5
  9. package/dist/cjs/index.cjs.js +3 -3
  10. package/dist/cjs/ion-app_8.cjs.entry.js +43 -5
  11. package/dist/cjs/ion-button_2.cjs.entry.js +3 -7
  12. package/dist/cjs/ion-input.cjs.entry.js +7 -15
  13. package/dist/cjs/ion-modal.cjs.entry.js +1 -1
  14. package/dist/cjs/ion-nav_2.cjs.entry.js +1 -1
  15. package/dist/cjs/ion-popover.cjs.entry.js +1 -1
  16. package/dist/cjs/ion-select_3.cjs.entry.js +56 -10
  17. package/dist/cjs/ion-textarea.cjs.entry.js +6 -14
  18. package/dist/cjs/ionic.cjs.js +1 -1
  19. package/dist/cjs/{ios.transition-j9CclgEW.js → ios.transition-BOt_uW73.js} +1 -1
  20. package/dist/cjs/loader.cjs.js +1 -1
  21. package/dist/cjs/{md.transition-CwFyRSfv.js → md.transition-Dt968VXB.js} +1 -1
  22. package/dist/cjs/{notch-controller-Bzqhjm4f.js → validity-C8QoAYT2.js} +14 -0
  23. package/dist/collection/components/button/button.js +3 -7
  24. package/dist/collection/components/header/header.ios.css +27 -1
  25. package/dist/collection/components/header/header.js +5 -4
  26. package/dist/collection/components/header/header.utils.js +37 -0
  27. package/dist/collection/components/input/input.js +6 -14
  28. package/dist/collection/components/select/select.js +59 -11
  29. package/dist/collection/components/textarea/textarea.js +5 -13
  30. package/dist/collection/utils/forms/index.js +1 -0
  31. package/dist/collection/utils/forms/validity.js +15 -0
  32. package/dist/collection/utils/transition/index.js +74 -3
  33. package/dist/docs.json +1 -1
  34. package/dist/esm/{index-D6G2seR8.js → index-r2D9DEro.js} +76 -5
  35. package/dist/esm/index.js +3 -3
  36. package/dist/esm/ion-app_8.entry.js +43 -5
  37. package/dist/esm/ion-button_2.entry.js +3 -7
  38. package/dist/esm/ion-input.entry.js +6 -14
  39. package/dist/esm/ion-modal.entry.js +1 -1
  40. package/dist/esm/ion-nav_2.entry.js +1 -1
  41. package/dist/esm/ion-popover.entry.js +1 -1
  42. package/dist/esm/ion-select_3.entry.js +55 -9
  43. package/dist/esm/ion-textarea.entry.js +5 -13
  44. package/dist/esm/ionic.js +1 -1
  45. package/dist/esm/{ios.transition-Bpq9ixwv.js → ios.transition-BDzw0_Hm.js} +1 -1
  46. package/dist/esm/loader.js +1 -1
  47. package/dist/esm/{md.transition-zOA0oanq.js → md.transition-BzDYi3qq.js} +1 -1
  48. package/dist/esm/{notch-controller-BwelN_JM.js → validity-B8oWougr.js} +14 -1
  49. package/dist/ionic/index.esm.js +1 -1
  50. package/dist/ionic/ionic.esm.js +1 -1
  51. package/dist/ionic/p-43ed1ef5.entry.js +4 -0
  52. package/dist/ionic/p-4c85d268.entry.js +4 -0
  53. package/dist/ionic/p-4cc26913.entry.js +4 -0
  54. package/dist/ionic/p-8bdfc8f6.entry.js +4 -0
  55. package/dist/ionic/{p-DPhQmGJN.js → p-C7hRNDhM.js} +1 -1
  56. package/dist/ionic/p-DUt5fQmA.js +4 -0
  57. package/dist/ionic/{p-9R1XyICs.js → p-DZRJwG4S.js} +1 -1
  58. package/dist/ionic/{p-DCv9sLH2.js → p-DieJyvMP.js} +1 -1
  59. package/dist/ionic/{p-c59314fd.entry.js → p-a80f1b04.entry.js} +1 -1
  60. package/dist/ionic/{p-c85c40ee.entry.js → p-dbbe606a.entry.js} +1 -1
  61. package/dist/ionic/{p-de7b5fa3.entry.js → p-e16b69e1.entry.js} +1 -1
  62. package/dist/ionic/p-f65f9308.entry.js +4 -0
  63. package/dist/types/components/header/header.utils.d.ts +10 -0
  64. package/dist/types/components/input/input.d.ts +0 -4
  65. package/dist/types/components/select/select.d.ts +6 -0
  66. package/dist/types/components/textarea/textarea.d.ts +0 -4
  67. package/dist/types/utils/forms/index.d.ts +1 -0
  68. package/dist/types/utils/forms/validity.d.ts +10 -0
  69. package/dist/types/utils/transition/index.d.ts +9 -0
  70. package/hydrate/index.js +161 -45
  71. package/hydrate/index.mjs +161 -45
  72. package/package.json +2 -2
  73. package/dist/ionic/p-1c8a476d.entry.js +0 -4
  74. package/dist/ionic/p-49f0149c.entry.js +0 -4
  75. package/dist/ionic/p-785026d7.entry.js +0 -4
  76. package/dist/ionic/p-78c74a3e.entry.js +0 -4
  77. package/dist/ionic/p-913a7c1e.entry.js +0 -4
  78. package/dist/ionic/p-CMhMiYSX.js +0 -4
package/hydrate/index.js CHANGED
@@ -9263,11 +9263,7 @@ class Button {
9263
9263
  target,
9264
9264
  };
9265
9265
  let fill = this.fill;
9266
- /**
9267
- * We check both undefined and null to
9268
- * work around https://github.com/ionic-team/stencil/issues/3586.
9269
- */
9270
- if (fill == null) {
9266
+ if (fill === undefined) {
9271
9267
  fill = this.inToolbar || this.inListHeader ? 'clear' : 'solid';
9272
9268
  }
9273
9269
  /**
@@ -9280,7 +9276,7 @@ class Button {
9280
9276
  {
9281
9277
  type !== 'button' && this.renderHiddenButton();
9282
9278
  }
9283
- return (hAsync(Host, { key: 'b105ad09215adb3ca2298acdadf0dc9154bbb9b0', onClick: this.handleClick, "aria-disabled": disabled ? 'true' : null, class: createColorClasses$1(color, {
9279
+ return (hAsync(Host, { key: 'ed82ea53705523f9afc5f1a9addff44cc6424f27', onClick: this.handleClick, "aria-disabled": disabled ? 'true' : null, class: createColorClasses$1(color, {
9284
9280
  [mode]: true,
9285
9281
  [buttonType]: true,
9286
9282
  [`${buttonType}-${expand}`]: expand !== undefined,
@@ -9295,7 +9291,7 @@ class Button {
9295
9291
  'button-disabled': disabled,
9296
9292
  'ion-activatable': true,
9297
9293
  'ion-focusable': true,
9298
- }) }, hAsync(TagType, Object.assign({ key: '66b4e7112bcb9e41d5a723fbbadb0a3104f9ee1d' }, attrs, { class: "button-native", part: "native", disabled: disabled, onFocus: this.onFocus, onBlur: this.onBlur }, inheritedAttributes), hAsync("span", { key: '1439fc3da280221028dcf7ce8ec9dab273c4d4bb', class: "button-inner" }, hAsync("slot", { key: 'd5269ae1afc87ec7b99746032f59cbae93720a9f', name: "icon-only", onSlotchange: this.slotChanged }), hAsync("slot", { key: '461c83e97aa246aa86d83e14f1e15a288d35041e', name: "start" }), hAsync("slot", { key: '807170d47101f9f6a333dd4ff489c89284f306fe' }), hAsync("slot", { key: 'e67f116dd0349a0d27893e4f3ff0ccef1d402f80', name: "end" })), mode === 'md' && hAsync("ion-ripple-effect", { key: '273f0bd9645a36c1bfd18a5c2ab4f81e22b7b989', type: this.rippleType }))));
9294
+ }) }, hAsync(TagType, Object.assign({ key: 'fadec13053469dd0405bbbc61b70ced568aa4826' }, attrs, { class: "button-native", part: "native", disabled: disabled, onFocus: this.onFocus, onBlur: this.onBlur }, inheritedAttributes), hAsync("span", { key: '6bf0e5144fb1148002e88038522402b789689d2c', class: "button-inner" }, hAsync("slot", { key: '25da0ca155cfa9e2754842c34f4fd09f576ac2d2', name: "icon-only", onSlotchange: this.slotChanged }), hAsync("slot", { key: '51414065bb11953ec9d818f8d9353589bc9072c5', name: "start" }), hAsync("slot", { key: 'c9b5f8842aeabd20628df2f4600f1257ea913d8d' }), hAsync("slot", { key: '478dd3671c7be1909fc84e672f0fa8dfe6082263', name: "end" })), mode === 'md' && hAsync("ion-ripple-effect", { key: 'e1d55f85a55144d743f58a5914cd116cb065fa8c', type: this.rippleType }))));
9299
9295
  }
9300
9296
  get el() { return getElement(this); }
9301
9297
  static get watchers() { return {
@@ -15229,6 +15225,8 @@ class Grid {
15229
15225
  }
15230
15226
 
15231
15227
  const TRANSITION = 'all 0.2s ease-in-out';
15228
+ const ROLE_NONE = 'none';
15229
+ const ROLE_BANNER = 'banner';
15232
15230
  const cloneElement = (tagName) => {
15233
15231
  const getCachedEl = document.querySelector(`${tagName}.ion-cloned-element`);
15234
15232
  if (getCachedEl !== null) {
@@ -15355,6 +15353,7 @@ const setHeaderActive = (headerIndex, active = true) => {
15355
15353
  const toolbars = headerIndex.toolbars;
15356
15354
  const ionTitles = toolbars.map((toolbar) => toolbar.ionTitleEl);
15357
15355
  if (active) {
15356
+ headerEl.setAttribute('role', ROLE_BANNER);
15358
15357
  headerEl.classList.remove('header-collapse-condense-inactive');
15359
15358
  ionTitles.forEach((ionTitle) => {
15360
15359
  if (ionTitle) {
@@ -15363,6 +15362,16 @@ const setHeaderActive = (headerIndex, active = true) => {
15363
15362
  });
15364
15363
  }
15365
15364
  else {
15365
+ /**
15366
+ * There can only be one banner landmark per page.
15367
+ * By default, all ion-headers have the banner role.
15368
+ * This causes an accessibility issue when using a
15369
+ * condensed header since there are two ion-headers
15370
+ * on the page at once (active and inactive).
15371
+ * To solve this, the role needs to be toggled
15372
+ * based on which header is active.
15373
+ */
15374
+ headerEl.setAttribute('role', ROLE_NONE);
15366
15375
  headerEl.classList.add('header-collapse-condense-inactive');
15367
15376
  /**
15368
15377
  * The small title should only be accessed by screen readers
@@ -15422,8 +15431,32 @@ const handleHeaderFade = (scrollEl, baseEl, condenseHeader) => {
15422
15431
  });
15423
15432
  });
15424
15433
  };
15434
+ /**
15435
+ * Get the role type for the ion-header.
15436
+ *
15437
+ * @param isInsideMenu If ion-header is inside ion-menu.
15438
+ * @param isCondensed If ion-header has collapse="condense".
15439
+ * @param mode The current mode.
15440
+ * @returns 'none' if inside ion-menu or if condensed in md
15441
+ * mode, otherwise 'banner'.
15442
+ */
15443
+ const getRoleType = (isInsideMenu, isCondensed, mode) => {
15444
+ // If the header is inside a menu, it should not have the banner role.
15445
+ if (isInsideMenu) {
15446
+ return ROLE_NONE;
15447
+ }
15448
+ /**
15449
+ * Only apply role="none" to `md` mode condensed headers
15450
+ * since the large header is never shown.
15451
+ */
15452
+ if (isCondensed && mode === 'md') {
15453
+ return ROLE_NONE;
15454
+ }
15455
+ // Default to banner role.
15456
+ return ROLE_BANNER;
15457
+ };
15425
15458
 
15426
- const headerIosCss = "ion-header{display:block;position:relative;-ms-flex-order:-1;order:-1;width:100%;z-index:10}ion-header ion-toolbar:first-of-type{padding-top:var(--ion-safe-area-top, 0)}.header-ios ion-toolbar:last-of-type{--border-width:0 0 0.55px}@supports ((-webkit-backdrop-filter: blur(0)) or (backdrop-filter: blur(0))){.header-background{left:0;right:0;top:0;bottom:0;position:absolute;-webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px)}.header-translucent-ios ion-toolbar{--opacity:.8}.header-collapse-condense-inactive .header-background{-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px)}}.header-ios.ion-no-border ion-toolbar:last-of-type{--border-width:0}.header-collapse-fade ion-toolbar{--opacity-scale:inherit}.header-collapse-condense{z-index:9}.header-collapse-condense ion-toolbar{position:-webkit-sticky;position:sticky;top:0}.header-collapse-condense ion-toolbar:first-of-type{padding-top:0px;z-index:1}.header-collapse-condense ion-toolbar{--background:var(--ion-background-color, #fff);z-index:0}.header-collapse-condense ion-toolbar:last-of-type{--border-width:0px}.header-collapse-condense ion-toolbar ion-searchbar{padding-top:0px;padding-bottom:13px}.header-collapse-main{--opacity-scale:1}.header-collapse-main ion-toolbar{--opacity-scale:inherit}.header-collapse-main ion-toolbar.in-toolbar ion-title,.header-collapse-main ion-toolbar.in-toolbar ion-buttons{-webkit-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out}.header-collapse-condense-inactive:not(.header-collapse-condense) ion-toolbar.in-toolbar ion-title,.header-collapse-condense-inactive:not(.header-collapse-condense) ion-toolbar.in-toolbar ion-buttons.buttons-collapse{opacity:0;pointer-events:none}.header-collapse-condense-inactive.header-collapse-condense ion-toolbar.in-toolbar ion-title,.header-collapse-condense-inactive.header-collapse-condense ion-toolbar.in-toolbar ion-buttons.buttons-collapse{visibility:hidden}ion-header.header-ios:not(.header-collapse-main):has(~ion-content ion-header.header-ios[collapse=condense],~ion-content ion-header.header-ios.header-collapse-condense){opacity:0}";
15459
+ const headerIosCss = "ion-header{display:block;position:relative;-ms-flex-order:-1;order:-1;width:100%;z-index:10}ion-header ion-toolbar:first-of-type{padding-top:var(--ion-safe-area-top, 0)}.header-ios ion-toolbar:last-of-type{--border-width:0 0 0.55px}@supports ((-webkit-backdrop-filter: blur(0)) or (backdrop-filter: blur(0))){.header-background{left:0;right:0;top:0;bottom:0;position:absolute;-webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px)}.header-translucent-ios ion-toolbar{--opacity:.8}.header-collapse-condense-inactive .header-background{-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px)}}.header-ios.ion-no-border ion-toolbar:last-of-type{--border-width:0}.header-collapse-fade ion-toolbar{--opacity-scale:inherit}.header-collapse-fade.header-transitioning ion-toolbar{--background:transparent;--border-style:none}.header-collapse-condense{z-index:9}.header-collapse-condense ion-toolbar{position:-webkit-sticky;position:sticky;top:0}.header-collapse-condense ion-toolbar:first-of-type{padding-top:0px;z-index:1}.header-collapse-condense ion-toolbar{z-index:0}.header-collapse-condense ion-toolbar:last-of-type{--border-width:0px}.header-collapse-condense ion-toolbar ion-searchbar{padding-top:0px;padding-bottom:13px}.header-collapse-main{--opacity-scale:1}.header-collapse-main ion-toolbar{--opacity-scale:inherit}.header-collapse-main ion-toolbar.in-toolbar ion-title,.header-collapse-main ion-toolbar.in-toolbar ion-buttons{-webkit-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out}.header-collapse-condense ion-toolbar,.header-collapse-condense-inactive.header-transitioning:not(.header-collapse-condense) ion-toolbar{--background:var(--ion-background-color, #fff)}.header-collapse-condense-inactive.header-transitioning:not(.header-collapse-condense) ion-toolbar{--border-style:none;--opacity-scale:1}.header-collapse-condense-inactive:not(.header-collapse-condense) ion-toolbar.in-toolbar ion-title,.header-collapse-condense-inactive:not(.header-collapse-condense) ion-toolbar.in-toolbar ion-buttons.buttons-collapse{opacity:0;pointer-events:none}.header-collapse-condense-inactive.header-collapse-condense ion-toolbar.in-toolbar ion-title,.header-collapse-condense-inactive.header-collapse-condense ion-toolbar.in-toolbar ion-buttons.buttons-collapse{visibility:hidden}ion-header.header-ios:not(.header-collapse-main):has(~ion-content ion-header.header-ios[collapse=condense],~ion-content ion-header.header-ios.header-collapse-condense){opacity:0}";
15427
15460
 
15428
15461
  const headerMdCss = "ion-header{display:block;position:relative;-ms-flex-order:-1;order:-1;width:100%;z-index:10}ion-header ion-toolbar:first-of-type{padding-top:var(--ion-safe-area-top, 0)}.header-md{-webkit-box-shadow:0 2px 4px -1px rgba(0, 0, 0, 0.2), 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12);box-shadow:0 2px 4px -1px rgba(0, 0, 0, 0.2), 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12)}.header-collapse-condense{display:none}.header-md.ion-no-border{-webkit-box-shadow:none;box-shadow:none}";
15429
15462
 
@@ -15566,16 +15599,17 @@ class Header {
15566
15599
  const { translucent, inheritedAttributes } = this;
15567
15600
  const mode = getIonMode$1(this);
15568
15601
  const collapse = this.collapse || 'none';
15602
+ const isCondensed = collapse === 'condense';
15569
15603
  // banner role must be at top level, so remove role if inside a menu
15570
- const roleType = hostContext('ion-menu', this.el) ? 'none' : 'banner';
15571
- return (hAsync(Host, Object.assign({ key: 'b6cc27f0b08afc9fcc889683525da765d80ba672', role: roleType, class: {
15604
+ const roleType = getRoleType(hostContext('ion-menu', this.el), isCondensed, mode);
15605
+ return (hAsync(Host, Object.assign({ key: '863c4568cd7b8c0ec55109f193bbbaed68a1346e', role: roleType, class: {
15572
15606
  [mode]: true,
15573
15607
  // Used internally for styling
15574
15608
  [`header-${mode}`]: true,
15575
15609
  [`header-translucent`]: this.translucent,
15576
15610
  [`header-collapse-${collapse}`]: true,
15577
15611
  [`header-translucent-${mode}`]: this.translucent,
15578
- } }, inheritedAttributes), mode === 'ios' && translucent && hAsync("div", { key: '395766d4dcee3398bc91960db21f922095292f14', class: "header-background" }), hAsync("slot", { key: '09a67ece27b258ff1248805d43d92a49b2c6859a' })));
15612
+ } }, inheritedAttributes), mode === 'ios' && translucent && hAsync("div", { key: '25c3bdce328b0b35607d154c8b8374679313d881', class: "header-background" }), hAsync("slot", { key: 'b44fab0a9be7920b9650da26117c783e751e1702' })));
15579
15613
  }
15580
15614
  get el() { return getElement(this); }
15581
15615
  static get style() { return {
@@ -16387,6 +16421,19 @@ const isOptionSelected = (currentValue, compareValue, compareWith) => {
16387
16421
  }
16388
16422
  };
16389
16423
 
16424
+ /**
16425
+ * Checks if the form element is in an invalid state based on
16426
+ * Ionic validation classes.
16427
+ *
16428
+ * @param el The form element to check.
16429
+ * @returns `true` if the element is invalid, `false` otherwise.
16430
+ */
16431
+ const checkInvalidState = (el) => {
16432
+ const hasIonTouched = el.classList.contains('ion-touched');
16433
+ const hasIonInvalid = el.classList.contains('ion-invalid');
16434
+ return hasIonTouched && hasIonInvalid;
16435
+ };
16436
+
16390
16437
  /**
16391
16438
  * Used to update a scoped component that uses emulated slots. This fires when
16392
16439
  * content is passed into the slot or when the content inside of a slot changes.
@@ -16752,20 +16799,12 @@ class Input {
16752
16799
  componentWillLoad() {
16753
16800
  this.inheritedAttributes = Object.assign(Object.assign({}, inheritAriaAttributes(this.el)), inheritAttributes$1(this.el, ['tabindex', 'title', 'data-form-type', 'dir']));
16754
16801
  }
16755
- /**
16756
- * Checks if the input is in an invalid state based on Ionic validation classes
16757
- */
16758
- checkInvalidState() {
16759
- const hasIonTouched = this.el.classList.contains('ion-touched');
16760
- const hasIonInvalid = this.el.classList.contains('ion-invalid');
16761
- return hasIonTouched && hasIonInvalid;
16762
- }
16763
16802
  connectedCallback() {
16764
16803
  const { el } = this;
16765
16804
  this.slotMutationController = createSlotMutationController(el, ['label', 'start', 'end'], () => forceUpdate());
16766
16805
  this.notchController = createNotchController(el, () => this.notchSpacerEl, () => this.labelSlot);
16767
16806
  // Always set initial state
16768
- this.isInvalid = this.checkInvalidState();
16807
+ this.isInvalid = checkInvalidState(el);
16769
16808
  this.debounceChanged();
16770
16809
  }
16771
16810
  componentDidLoad() {
@@ -17019,7 +17058,7 @@ class Input {
17019
17058
  * TODO(FW-5592): Remove hasStartEndSlots condition
17020
17059
  */
17021
17060
  const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || hasFocus || hasStartEndSlots));
17022
- return (hAsync(Host, { key: '8a51f0300d5bc66392f9ab9a6fa0b5d388072a33', class: createColorClasses$1(this.color, {
17061
+ return (hAsync(Host, { key: '97b5308021064d9e7434ef2d3d96f27045c1b0c4', class: createColorClasses$1(this.color, {
17023
17062
  [mode]: true,
17024
17063
  'has-value': hasValue,
17025
17064
  'has-focus': hasFocus,
@@ -17030,14 +17069,14 @@ class Input {
17030
17069
  'in-item': inItem,
17031
17070
  'in-item-color': hostContext('ion-item.ion-color', this.el),
17032
17071
  'input-disabled': disabled,
17033
- }) }, hAsync("label", { key: '9f8cf88d7d0e27931b51bd9c67f048c7fc6f5703', class: "input-wrapper", htmlFor: inputId, onClick: this.onLabelClick }, this.renderLabelContainer(), hAsync("div", { key: '7ad30bf9777774062a6ccf9a3ba804f251eef1bb', class: "native-wrapper", onClick: this.onLabelClick }, hAsync("slot", { key: '8af0b0325d101df8eed7d24f2767d6ca4d307319', name: "start" }), hAsync("input", Object.assign({ key: '1c53f7f9fa2567f3df19681cf4e7c21be382eae6', 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.isInvalid ? 'true' : undefined }, this.inheritedAttributes)), this.clearInput && !readonly && !disabled && (hAsync("button", { key: 'b081d0e1ec1444b4c9cca145fc9cd2ad4a68b3da', "aria-label": "reset", type: "button", class: "input-clear-icon", onPointerDown: (ev) => {
17072
+ }) }, hAsync("label", { key: '353f68726ce180299bd9adc81e5ff7d26a48f54f', class: "input-wrapper", htmlFor: inputId, onClick: this.onLabelClick }, this.renderLabelContainer(), hAsync("div", { key: '2034b4bad04fc157f3298a1805819216b6f439d0', class: "native-wrapper", onClick: this.onLabelClick }, hAsync("slot", { key: '96bb5e30176b2bd76dfb75bfbf6c1c3d4403f4bb', name: "start" }), hAsync("input", Object.assign({ key: '1a1d75b0e414a95c89d5a760757c33548d234aca', 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.isInvalid ? 'true' : undefined }, this.inheritedAttributes)), this.clearInput && !readonly && !disabled && (hAsync("button", { key: '95f3df17b7691d9a2e7dcd4a51f16a94aa3ca36f', "aria-label": "reset", type: "button", class: "input-clear-icon", onPointerDown: (ev) => {
17034
17073
  /**
17035
17074
  * This prevents mobile browsers from
17036
17075
  * blurring the input when the clear
17037
17076
  * button is activated.
17038
17077
  */
17039
17078
  ev.preventDefault();
17040
- }, onClick: this.clearTextInput }, hAsync("ion-icon", { key: '01535299241c3635460c05646420acf62a1ff567', "aria-hidden": "true", icon: clearIconData }))), hAsync("slot", { key: '480f3eb58b08ae792866a5b9b4c068748c5567cc', name: "end" })), shouldRenderHighlight && hAsync("div", { key: 'a8609cacee88e4a09f1cca65b6a47cb79a56f35e', class: "input-highlight" })), this.renderBottomContent()));
17079
+ }, onClick: this.clearTextInput }, hAsync("ion-icon", { key: '16b0af75eed50c8115fb5597f73b5fbf71c2530e', "aria-hidden": "true", icon: clearIconData }))), hAsync("slot", { key: 'c48da0f8ddb3764ac43efa705bb4a6bb2d9cc2fd', name: "end" })), shouldRenderHighlight && hAsync("div", { key: 'f15238481fc20de56ca7ecb6e350b3c024cc755e', class: "input-highlight" })), this.renderBottomContent()));
17041
17080
  }
17042
17081
  get el() { return getElement(this); }
17043
17082
  static get watchers() { return {
@@ -20676,11 +20715,22 @@ const iosTransitionAnimation$1 = () => Promise.resolve().then(function () { retu
20676
20715
  const mdTransitionAnimation$1 = () => Promise.resolve().then(function () { return md_transition; });
20677
20716
  const focusController = createFocusController();
20678
20717
  // TODO(FW-2832): types
20718
+ /**
20719
+ * Executes the main page transition.
20720
+ * It also manages the lifecycle of header visibility (if any)
20721
+ * to prevent visual flickering in iOS. The flickering only
20722
+ * occurs for a condensed header that is placed above the content.
20723
+ *
20724
+ * @param opts Options for the transition.
20725
+ * @returns A promise that resolves when the transition is complete.
20726
+ */
20679
20727
  const transition = (opts) => {
20680
20728
  return new Promise((resolve, reject) => {
20681
20729
  writeTask(() => {
20682
- beforeTransition(opts);
20683
- runTransition(opts).then((result) => {
20730
+ const transitioningInactiveHeader = getIosIonHeader(opts);
20731
+ beforeTransition(opts, transitioningInactiveHeader);
20732
+ runTransition(opts)
20733
+ .then((result) => {
20684
20734
  if (result.animation) {
20685
20735
  result.animation.destroy();
20686
20736
  }
@@ -20689,15 +20739,21 @@ const transition = (opts) => {
20689
20739
  }, (error) => {
20690
20740
  afterTransition(opts);
20691
20741
  reject(error);
20742
+ })
20743
+ .finally(() => {
20744
+ // Ensure that the header is restored to its original state.
20745
+ setHeaderTransitionClass(transitioningInactiveHeader, false);
20692
20746
  });
20693
20747
  });
20694
20748
  });
20695
20749
  };
20696
- const beforeTransition = (opts) => {
20750
+ const beforeTransition = (opts, transitioningInactiveHeader) => {
20697
20751
  const enteringEl = opts.enteringEl;
20698
20752
  const leavingEl = opts.leavingEl;
20699
20753
  focusController.saveViewFocus(leavingEl);
20700
20754
  setZIndex(enteringEl, leavingEl, opts.direction);
20755
+ // Prevent flickering of the header by adding a class.
20756
+ setHeaderTransitionClass(transitioningInactiveHeader, true);
20701
20757
  if (opts.showGoBack) {
20702
20758
  enteringEl.classList.add('can-go-back');
20703
20759
  }
@@ -20886,6 +20942,39 @@ const setZIndex = (enteringEl, leavingEl, direction) => {
20886
20942
  leavingEl.style.zIndex = '100';
20887
20943
  }
20888
20944
  };
20945
+ /**
20946
+ * Add a class to ensure that the header (if any)
20947
+ * does not flicker during the transition. By adding the
20948
+ * transitioning class, we ensure that the header has
20949
+ * the necessary styles to prevent the following flickers:
20950
+ * 1. When entering a page with a condensed header, the
20951
+ * header should never be visible. However,
20952
+ * it briefly renders the background color while
20953
+ * the transition is occurring.
20954
+ * 2. When leaving a page with a condensed header, the
20955
+ * header has an opacity of 0 and the pages
20956
+ * have a z-index which causes the entering page to
20957
+ * briefly show it's content underneath the leaving page.
20958
+ * 3. When entering a page or leaving a page with a fade
20959
+ * header, the header should not have a background color.
20960
+ * However, it briefly shows the background color while
20961
+ * the transition is occurring.
20962
+ *
20963
+ * @param header The header element to modify.
20964
+ * @param isTransitioning Whether the transition is occurring.
20965
+ */
20966
+ const setHeaderTransitionClass = (header, isTransitioning) => {
20967
+ if (!header) {
20968
+ return;
20969
+ }
20970
+ const transitionClass = 'header-transitioning';
20971
+ if (isTransitioning) {
20972
+ header.classList.add(transitionClass);
20973
+ }
20974
+ else {
20975
+ header.classList.remove(transitionClass);
20976
+ }
20977
+ };
20889
20978
  const getIonPageElement = (element) => {
20890
20979
  if (element.classList.contains('ion-page')) {
20891
20980
  return element;
@@ -20897,6 +20986,27 @@ const getIonPageElement = (element) => {
20897
20986
  // idk, return the original element so at least something animates and we don't have a null pointer
20898
20987
  return element;
20899
20988
  };
20989
+ /**
20990
+ * Retrieves the ion-header element from a page based on the
20991
+ * direction of the transition.
20992
+ *
20993
+ * @param opts Options for the transition.
20994
+ * @returns The ion-header element or null if not found or not in 'ios' mode.
20995
+ */
20996
+ const getIosIonHeader = (opts) => {
20997
+ const enteringEl = opts.enteringEl;
20998
+ const leavingEl = opts.leavingEl;
20999
+ const direction = opts.direction;
21000
+ const mode = opts.mode;
21001
+ if (mode !== 'ios') {
21002
+ return null;
21003
+ }
21004
+ const element = direction === 'back' ? leavingEl : enteringEl;
21005
+ if (!element) {
21006
+ return null;
21007
+ }
21008
+ return element.querySelector('ion-header');
21009
+ };
20900
21010
 
20901
21011
  const KEYBOARD_DID_OPEN = 'ionKeyboardDidShow';
20902
21012
 
@@ -33058,6 +33168,10 @@ class Select {
33058
33168
  * is applied in both cases.
33059
33169
  */
33060
33170
  this.hasFocus = false;
33171
+ /**
33172
+ * Track validation state for proper aria-live announcements.
33173
+ */
33174
+ this.isInvalid = false;
33061
33175
  /**
33062
33176
  * The text to display on the cancel button.
33063
33177
  */
@@ -33180,9 +33294,12 @@ class Select {
33180
33294
  this.mutationO = watchForOptions(this.el, 'ion-select-option', async () => {
33181
33295
  this.updateOverlayOptions();
33182
33296
  });
33297
+ // Always set initial state
33298
+ this.isInvalid = checkInvalidState(this.el);
33183
33299
  }
33184
33300
  componentWillLoad() {
33185
33301
  this.inheritedAttributes = inheritAttributes$1(this.el, ['aria-label']);
33302
+ this.hintTextID = this.getHintTextID();
33186
33303
  }
33187
33304
  componentDidLoad() {
33188
33305
  /**
@@ -33206,6 +33323,11 @@ class Select {
33206
33323
  this.notchController.destroy();
33207
33324
  this.notchController = undefined;
33208
33325
  }
33326
+ // Clean up validation observer to prevent memory leaks.
33327
+ if (this.validationObserver) {
33328
+ this.validationObserver.disconnect();
33329
+ this.validationObserver = undefined;
33330
+ }
33209
33331
  }
33210
33332
  /**
33211
33333
  * Open the select overlay. The overlay is either an alert, action sheet, or popover,
@@ -33676,11 +33798,11 @@ class Select {
33676
33798
  }
33677
33799
  renderListbox() {
33678
33800
  const { disabled, inputId, isExpanded, required } = this;
33679
- return (hAsync("button", { disabled: disabled, id: inputId, "aria-label": this.ariaLabel, "aria-haspopup": "dialog", "aria-expanded": `${isExpanded}`, "aria-describedby": this.getHintTextID(), "aria-invalid": this.getHintTextID() === this.errorTextId, "aria-required": `${required}`, onFocus: this.onFocus, onBlur: this.onBlur, ref: (focusEl) => (this.focusEl = focusEl) }));
33801
+ return (hAsync("button", { disabled: disabled, id: inputId, "aria-label": this.ariaLabel, "aria-haspopup": "dialog", "aria-expanded": `${isExpanded}`, "aria-describedby": this.hintTextID, "aria-invalid": this.isInvalid ? 'true' : undefined, "aria-required": `${required}`, onFocus: this.onFocus, onBlur: this.onBlur, ref: (focusEl) => (this.focusEl = focusEl) }));
33680
33802
  }
33681
33803
  getHintTextID() {
33682
- const { el, helperText, errorText, helperTextId, errorTextId } = this;
33683
- if (el.classList.contains('ion-touched') && el.classList.contains('ion-invalid') && errorText) {
33804
+ const { helperText, errorText, helperTextId, errorTextId, isInvalid } = this;
33805
+ if (isInvalid && errorText) {
33684
33806
  return errorTextId;
33685
33807
  }
33686
33808
  if (helperText) {
@@ -33692,10 +33814,10 @@ class Select {
33692
33814
  * Renders the helper text or error text values
33693
33815
  */
33694
33816
  renderHintText() {
33695
- const { helperText, errorText, helperTextId, errorTextId } = this;
33817
+ const { helperText, errorText, helperTextId, errorTextId, isInvalid } = this;
33696
33818
  return [
33697
- hAsync("div", { id: helperTextId, class: "helper-text", part: "supporting-text helper-text" }, helperText),
33698
- hAsync("div", { id: errorTextId, class: "error-text", part: "supporting-text error-text" }, errorText),
33819
+ hAsync("div", { id: helperTextId, class: "helper-text", part: "supporting-text helper-text", "aria-live": "polite" }, !isInvalid ? helperText : null),
33820
+ hAsync("div", { id: errorTextId, class: "error-text", part: "supporting-text error-text", role: "alert" }, isInvalid ? errorText : null),
33699
33821
  ];
33700
33822
  }
33701
33823
  /**
@@ -33743,7 +33865,7 @@ class Select {
33743
33865
  * TODO(FW-5592): Remove hasStartEndSlots condition
33744
33866
  */
33745
33867
  const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || isExpanded || hasStartEndSlots));
33746
- return (hAsync(Host, { key: 'c03fb65e8fc9f9aab295e07b282377d57d910519', onClick: this.onClick, class: createColorClasses$1(this.color, {
33868
+ return (hAsync(Host, { key: '35b5e18e6f79a802ff2d46d1242e80ff755cc0b9', onClick: this.onClick, class: createColorClasses$1(this.color, {
33747
33869
  [mode]: true,
33748
33870
  'in-item': inItem,
33749
33871
  'in-item-color': hostContext('ion-item.ion-color', el),
@@ -33761,7 +33883,7 @@ class Select {
33761
33883
  [`select-justify-${justify}`]: justifyEnabled,
33762
33884
  [`select-shape-${shape}`]: shape !== undefined,
33763
33885
  [`select-label-placement-${labelPlacement}`]: true,
33764
- }) }, hAsync("label", { key: '0d0c8ec55269adcac625f2899a547f4e7f3e3741', class: "select-wrapper", id: "select-label", onClick: this.onLabelClick }, this.renderLabelContainer(), hAsync("div", { key: 'f6dfc93c0e23cbe75a2947abde67d842db2dad78', class: "select-wrapper-inner" }, hAsync("slot", { key: '957bfadf9f101f519091419a362d3abdc2be66f6', name: "start" }), hAsync("div", { key: 'ca349202a484e7f2e884533fd330f0b136754f7d', class: "native-wrapper", ref: (el) => (this.nativeWrapperEl = el), part: "container" }, this.renderSelectText(), this.renderListbox()), hAsync("slot", { key: 'f0e62a6533ff1c8f62bd2d27f60b23385c4fa9ed', name: "end" }), !hasFloatingOrStackedLabel && this.renderSelectIcon()), hasFloatingOrStackedLabel && this.renderSelectIcon(), shouldRenderHighlight && hAsync("div", { key: 'fb840d46bafafb09898ebeebbe8c181906a3d8a2', class: "select-highlight" })), this.renderBottomContent()));
33886
+ }) }, hAsync("label", { key: '6005b34a0c50bc4d7653a4276bc232ecd02e083c', class: "select-wrapper", id: "select-label", onClick: this.onLabelClick }, this.renderLabelContainer(), hAsync("div", { key: 'c7e07aa81ae856c057f16275dd058f37c5670a47', class: "select-wrapper-inner" }, hAsync("slot", { key: '7fc2deefe0424404caacdbbd9e08ed43ba55d28a', name: "start" }), hAsync("div", { key: '157d74ee717b1bc30b5f1c233a09b0c8456aa68e', class: "native-wrapper", ref: (el) => (this.nativeWrapperEl = el), part: "container" }, this.renderSelectText(), this.renderListbox()), hAsync("slot", { key: 'ea66db304528b82bf9317730b6dce3db2612f235', name: "end" }), !hasFloatingOrStackedLabel && this.renderSelectIcon()), hasFloatingOrStackedLabel && this.renderSelectIcon(), shouldRenderHighlight && hAsync("div", { key: '786eb1530b7476f0615d4e7c0bf4e7e4dc66509c', class: "select-highlight" })), this.renderBottomContent()));
33765
33887
  }
33766
33888
  get el() { return getElement(this); }
33767
33889
  static get watchers() { return {
@@ -33802,6 +33924,8 @@ class Select {
33802
33924
  "required": [4],
33803
33925
  "isExpanded": [32],
33804
33926
  "hasFocus": [32],
33927
+ "isInvalid": [32],
33928
+ "hintTextID": [32],
33805
33929
  "open": [64]
33806
33930
  },
33807
33931
  "$listeners$": undefined,
@@ -34989,20 +35113,12 @@ class Textarea {
34989
35113
  this.el.click();
34990
35114
  }
34991
35115
  }
34992
- /**
34993
- * Checks if the textarea is in an invalid state based on Ionic validation classes
34994
- */
34995
- checkValidationState() {
34996
- const hasIonTouched = this.el.classList.contains('ion-touched');
34997
- const hasIonInvalid = this.el.classList.contains('ion-invalid');
34998
- return hasIonTouched && hasIonInvalid;
34999
- }
35000
35116
  connectedCallback() {
35001
35117
  const { el } = this;
35002
35118
  this.slotMutationController = createSlotMutationController(el, ['label', 'start', 'end'], () => forceUpdate());
35003
35119
  this.notchController = createNotchController(el, () => this.notchSpacerEl, () => this.labelSlot);
35004
35120
  // Always set initial state
35005
- this.isInvalid = this.checkValidationState();
35121
+ this.isInvalid = checkInvalidState(this.el);
35006
35122
  this.debounceChanged();
35007
35123
  }
35008
35124
  disconnectedCallback() {
@@ -35256,7 +35372,7 @@ class Textarea {
35256
35372
  * TODO(FW-5592): Remove hasStartEndSlots condition
35257
35373
  */
35258
35374
  const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || hasFocus || hasStartEndSlots));
35259
- return (hAsync(Host, { key: '26b46666a92b3f652775bb1c46661f9a30392104', class: createColorClasses$1(this.color, {
35375
+ return (hAsync(Host, { key: 'a70a62d7aae3831a50acd74f60b930925ada1326', class: createColorClasses$1(this.color, {
35260
35376
  [mode]: true,
35261
35377
  'has-value': hasValue,
35262
35378
  'has-focus': hasFocus,
@@ -35265,7 +35381,7 @@ class Textarea {
35265
35381
  [`textarea-shape-${shape}`]: shape !== undefined,
35266
35382
  [`textarea-label-placement-${labelPlacement}`]: true,
35267
35383
  'textarea-disabled': disabled,
35268
- }) }, hAsync("label", { key: '2649da816216959ebe1f34cafd9dedbac20ec3c2', class: "textarea-wrapper", htmlFor: inputId, onClick: this.onLabelClick }, this.renderLabelContainer(), hAsync("div", { key: 'dca98593efece1b044dbcda045fa70882d715cb2', class: "textarea-wrapper-inner" }, hAsync("div", { key: '2019daf87fddca5ec0b2e336f0376fd9642bae1b', class: "start-slot-wrapper" }, hAsync("slot", { key: '36c423c394a71d08261705b9d6729e756bf65924', name: "start" })), hAsync("div", { key: '0c3ea34105c7eddfa4094371c5d288c50ed10db3', class: "native-wrapper", ref: (el) => (this.textareaWrapper = el) }, hAsync("textarea", Object.assign({ key: 'ce173b83b16aff43d293fa1edef9b66c6676227b', 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.isInvalid ? 'true' : undefined }, this.inheritedAttributes), value)), hAsync("div", { key: '756e343cfd208bb5ad9ecf08d77cbb0a9606dc7b', class: "end-slot-wrapper" }, hAsync("slot", { key: '0eb596814a037fa4634ff8c5bac0045540edfe21', name: "end" }))), shouldRenderHighlight && hAsync("div", { key: 'df62f896eb6e0e2d1217aa487c198eb82a52bcb8', class: "textarea-highlight" })), this.renderBottomContent()));
35384
+ }) }, hAsync("label", { key: '8a2dd59a60f7469df84018eb0ede3a9ec3862703', class: "textarea-wrapper", htmlFor: inputId, onClick: this.onLabelClick }, this.renderLabelContainer(), hAsync("div", { key: '1bfc368236e3da7a225a45118c27fbfc1fe5fa46', class: "textarea-wrapper-inner" }, hAsync("div", { key: '215cbb2635ff52e31a8973376989b85e7245d40f', class: "start-slot-wrapper" }, hAsync("slot", { key: '9f6b461cdee9d629deb695d2bea054ece2f32305', name: "start" })), hAsync("div", { key: 'c1af35a2d5bc452bebe0b22a26d15ff52b4e9fc8', class: "native-wrapper", ref: (el) => (this.textareaWrapper = el) }, hAsync("textarea", Object.assign({ key: '69a69b3cf0932baafbe37e6e846f1a571608d3f2', 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.isInvalid ? 'true' : undefined }, this.inheritedAttributes), value)), hAsync("div", { key: 'c053ea8b865d0e29763aed2e4939cc9c9e374c15', class: "end-slot-wrapper" }, hAsync("slot", { key: '930aa641833b0df54b9ea10368fc2f46d5f491f6', name: "end" }))), shouldRenderHighlight && hAsync("div", { key: '8d12597d15f5f429d80e8272ea99e64ed924e482', class: "textarea-highlight" })), this.renderBottomContent()));
35269
35385
  }
35270
35386
  get el() { return getElement(this); }
35271
35387
  static get watchers() { return {