@ionic/core 9.0.9 → 9.0.10-dev.11793383958.19a7d413

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 (43) hide show
  1. package/components/ion-input-otp.js +1 -1
  2. package/components/ion-menu.js +1 -1
  3. package/components/ion-router.js +1 -1
  4. package/dist/cjs/ion-input-otp.cjs.entry.js +126 -10
  5. package/dist/cjs/ion-menu_3.cjs.entry.js +25 -7
  6. package/dist/cjs/ion-route_4.cjs.entry.js +121 -16
  7. package/dist/cjs/ionic.cjs.js +1 -1
  8. package/dist/cjs/loader.cjs.js +1 -1
  9. package/dist/collection/components/input-otp/input-otp.ios.css +30 -5
  10. package/dist/collection/components/input-otp/input-otp.js +191 -12
  11. package/dist/collection/components/input-otp/input-otp.md.css +30 -5
  12. package/dist/collection/components/menu/menu.js +25 -8
  13. package/dist/collection/components/route/route.js +9 -1
  14. package/dist/collection/components/route-redirect/route-redirect.js +1 -1
  15. package/dist/collection/components/router/utils/constants.js +2 -0
  16. package/dist/collection/components/router/utils/matching.js +97 -14
  17. package/dist/collection/components/router/utils/path.js +17 -3
  18. package/dist/docs.json +92 -3
  19. package/dist/esm/ion-input-otp.entry.js +128 -12
  20. package/dist/esm/ion-menu_3.entry.js +26 -8
  21. package/dist/esm/ion-route_4.entry.js +121 -16
  22. package/dist/esm/ionic.js +1 -1
  23. package/dist/esm/loader.js +1 -1
  24. package/dist/html.html-data.json +10 -2
  25. package/dist/ionic/ionic.esm.js +1 -1
  26. package/dist/ionic/p-095da8ec.entry.js +4 -0
  27. package/dist/ionic/p-705759fd.entry.js +4 -0
  28. package/dist/ionic/p-99c518de.entry.js +4 -0
  29. package/dist/types/components/input-otp/input-otp-interface.d.ts +1 -0
  30. package/dist/types/components/input-otp/input-otp.d.ts +40 -2
  31. package/dist/types/components/menu/menu.d.ts +7 -0
  32. package/dist/types/components/route/route.d.ts +8 -0
  33. package/dist/types/components/route-redirect/route-redirect.d.ts +3 -1
  34. package/dist/types/components/router/utils/constants.d.ts +2 -0
  35. package/dist/types/components/router/utils/matching.d.ts +10 -0
  36. package/dist/types/components/router/utils/path.d.ts +5 -1
  37. package/dist/types/components.d.ts +32 -6
  38. package/hydrate/index.js +257 -33
  39. package/hydrate/index.mjs +257 -33
  40. package/package.json +1 -1
  41. package/dist/ionic/p-539d6c8e.entry.js +0 -4
  42. package/dist/ionic/p-7ce9c6f8.entry.js +0 -4
  43. package/dist/ionic/p-af11d3c6.entry.js +0 -4
@@ -1,15 +1,17 @@
1
1
  /*!
2
2
  * (C) Ionic http://ionicframework.com - MIT License
3
3
  */
4
- import { r as registerInstance, d as createEvent, a as printIonWarning, h, F as Fragment, f as Host, g as getElement } from './index-BpRUsN_W.js';
5
- import { i as inheritAriaAttributes } from './helpers-BJqKF1pr.js';
4
+ import { r as registerInstance, d as createEvent, j as forceUpdate, a as printIonWarning, h, c as printIonError, F as Fragment, f as Host, g as getElement } from './index-BpRUsN_W.js';
5
+ import { a as createAttributeController } from './attribute-controller-DPMIcbef.js';
6
+ import { q as ariaAttributes } from './helpers-BJqKF1pr.js';
6
7
  import { i as isRTL } from './dir-Dojwmvde.js';
8
+ import { c as checkInvalidState } from './validity-DJztqcrH.js';
7
9
  import { c as createColorClasses } from './theme-byZM6qHV.js';
8
10
  import { b as getIonMode } from './ionic-global-Cep6oYzK.js';
9
11
 
10
- const inputOtpIosCss = () => `.sc-ion-input-otp-ios-h{--margin-top:0;--margin-end:0;--margin-bottom:0;--margin-start:0;--padding-top:16px;--padding-end:0;--padding-bottom:16px;--padding-start:0;--color:initial;--min-width:40px;--separator-width:8px;--separator-height:var(--separator-width);--separator-border-radius:999px;--separator-color:var(--ion-color-step-150, var(--ion-background-color-step-150, #d9d9d9));--highlight-color-focused:var(--ion-color-primary, #0054e9);--highlight-color-valid:var(--ion-color-success, #2dd55b);--highlight-color-invalid:var(--ion-color-danger, #c5000f);--highlight-color:var(--highlight-color-focused);display:block;position:relative;font-size:0.875rem}.input-otp-group.sc-ion-input-otp-ios{-webkit-margin-start:var(--margin-start);margin-inline-start:var(--margin-start);-webkit-margin-end:var(--margin-end);margin-inline-end:var(--margin-end);margin-top:var(--margin-top);margin-bottom:var(--margin-bottom);-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.native-wrapper.sc-ion-input-otp-ios{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;min-width:var(--min-width)}.native-input.sc-ion-input-otp-ios{border-radius:var(--border-radius);width:var(--width);min-width:inherit;height:var(--height);border-width:var(--border-width);border-style:solid;border-color:var(--border-color);background:var(--background);color:var(--color);font-size:inherit;text-align:center;-webkit-appearance:none;-moz-appearance:none;appearance:none}.has-focus.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios{caret-color:var(--highlight-color)}.input-otp-description.sc-ion-input-otp-ios{color:var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d));font-size:0.75rem;line-height:1.25rem;text-align:center}.input-otp-description-hidden.sc-ion-input-otp-ios{display:none}.input-otp-separator.sc-ion-input-otp-ios{border-radius:var(--separator-border-radius);-ms-flex-negative:0;flex-shrink:0;width:var(--separator-width);height:var(--separator-height);background:var(--separator-color)}.input-otp-size-small.sc-ion-input-otp-ios-h{--width:40px;--height:40px}.input-otp-size-small.sc-ion-input-otp-ios-h .input-otp-group.sc-ion-input-otp-ios{gap:8px}.input-otp-size-medium.sc-ion-input-otp-ios-h{--width:48px;--height:48px}.input-otp-size-large.sc-ion-input-otp-ios-h{--width:56px;--height:56px}.input-otp-size-medium.sc-ion-input-otp-ios-h .input-otp-group.sc-ion-input-otp-ios,.input-otp-size-large.sc-ion-input-otp-ios-h .input-otp-group.sc-ion-input-otp-ios{gap:12px}.input-otp-shape-round.sc-ion-input-otp-ios-h{--border-radius:16px}.input-otp-shape-soft.sc-ion-input-otp-ios-h{--border-radius:8px}.input-otp-shape-rectangular.sc-ion-input-otp-ios-h{--border-radius:0}.input-otp-fill-outline.sc-ion-input-otp-ios-h{--background:none}.input-otp-fill-solid.sc-ion-input-otp-ios-h{--border-color:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2));--background:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2))}.input-otp-disabled.sc-ion-input-otp-ios-h{--color:var(--ion-color-step-350, var(--ion-text-color-step-650, #a6a6a6))}.input-otp-fill-outline.input-otp-disabled.sc-ion-input-otp-ios-h{--background:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2));--border-color:var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6))}.input-otp-disabled.sc-ion-input-otp-ios-h,.input-otp-disabled.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios:disabled{cursor:not-allowed}.has-focus.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios:focus{--border-color:var(--highlight-color);outline:none}.input-otp-fill-outline.input-otp-readonly.sc-ion-input-otp-ios-h{--background:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2))}.input-otp-fill-solid.input-otp-disabled.sc-ion-input-otp-ios-h,.input-otp-fill-solid.input-otp-readonly.sc-ion-input-otp-ios-h{--border-color:var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6));--background:var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6))}.ion-touched.ion-invalid.sc-ion-input-otp-ios-h{--highlight-color:var(--highlight-color-invalid)}.ion-valid.sc-ion-input-otp-ios-h{--highlight-color:var(--highlight-color-valid)}.has-focus.ion-valid.sc-ion-input-otp-ios-h,.ion-touched.ion-invalid.sc-ion-input-otp-ios-h{--border-color:var(--highlight-color)}.ion-color.sc-ion-input-otp-ios-h{--highlight-color-focused:var(--ion-color-base)}.input-otp-fill-outline.ion-color.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios,.input-otp-fill-solid.ion-color.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios:focus{border-color:rgba(var(--ion-color-base-rgb), 0.6)}.input-otp-fill-outline.ion-color.ion-invalid.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios,.input-otp-fill-solid.ion-color.ion-invalid.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios,.input-otp-fill-outline.ion-color.has-focus.ion-invalid.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios,.input-otp-fill-solid.ion-color.has-focus.ion-invalid.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios{border-color:var(--ion-color-danger, #c5000f)}.input-otp-fill-outline.ion-color.ion-valid.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios,.input-otp-fill-solid.ion-color.ion-valid.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios,.input-otp-fill-outline.ion-color.has-focus.ion-valid.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios,.input-otp-fill-solid.ion-color.has-focus.ion-valid.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios{border-color:var(--ion-color-success, #2dd55b)}.input-otp-fill-outline.input-otp-disabled.ion-color.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios{border-color:rgba(var(--ion-color-base-rgb), 0.3)}.sc-ion-input-otp-ios-h{--border-width:0.55px}.has-focus.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios:focus{--border-width:1px}.input-otp-fill-outline.sc-ion-input-otp-ios-h{--border-color:var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-250, var(--ion-background-color-step-250, #c8c7cc))))}`;
12
+ const inputOtpIosCss = () => `.sc-ion-input-otp-ios-h{--margin-top:0;--margin-end:0;--margin-bottom:0;--margin-start:0;--padding-top:16px;--padding-end:0;--padding-bottom:16px;--padding-start:0;--color:initial;--min-width:40px;--separator-width:8px;--separator-height:var(--separator-width);--separator-border-radius:999px;--separator-color:var(--ion-color-step-150, var(--ion-background-color-step-150, #d9d9d9));--highlight-color-focused:var(--ion-color-primary, #0054e9);--highlight-color-valid:var(--ion-color-success, #2dd55b);--highlight-color-invalid:var(--ion-color-danger, #c5000f);--highlight-color:var(--highlight-color-focused);--border-color:initial;display:block;position:relative;font-size:0.875rem}.input-otp-group.sc-ion-input-otp-ios{-webkit-margin-start:var(--margin-start);margin-inline-start:var(--margin-start);-webkit-margin-end:var(--margin-end);margin-inline-end:var(--margin-end);margin-top:var(--margin-top);margin-bottom:var(--margin-bottom);-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.native-wrapper.sc-ion-input-otp-ios{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;min-width:var(--min-width)}.native-input.sc-ion-input-otp-ios{border-radius:var(--border-radius);width:var(--width);min-width:inherit;height:var(--height);border-width:var(--border-width);border-style:solid;border-color:var(--border-color, var(--internal-border-color));background:var(--background);color:var(--color);font-size:inherit;text-align:center;-webkit-appearance:none;-moz-appearance:none;appearance:none}.has-focus.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios{caret-color:var(--highlight-color)}.input-otp-description.sc-ion-input-otp-ios{color:var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d));font-size:0.75rem;line-height:1.25rem;text-align:center}.input-otp-description-hidden.sc-ion-input-otp-ios{display:none}.input-otp-bottom.sc-ion-input-otp-ios{font-size:0.75rem;line-height:1.25rem;text-align:center}.input-otp-bottom.sc-ion-input-otp-ios .error-text.sc-ion-input-otp-ios{display:none;color:var(--highlight-color-invalid)}.input-otp-bottom.sc-ion-input-otp-ios .helper-text.sc-ion-input-otp-ios{display:block;color:var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d))}.ion-touched.ion-invalid.sc-ion-input-otp-ios-h .input-otp-bottom.sc-ion-input-otp-ios .error-text.sc-ion-input-otp-ios{display:block}.ion-touched.ion-invalid.sc-ion-input-otp-ios-h .input-otp-bottom.sc-ion-input-otp-ios .helper-text.sc-ion-input-otp-ios{display:none}.input-otp-separator.sc-ion-input-otp-ios{border-radius:var(--separator-border-radius);-ms-flex-negative:0;flex-shrink:0;width:var(--separator-width);height:var(--separator-height);background:var(--separator-color)}.input-otp-size-small.sc-ion-input-otp-ios-h{--width:40px;--height:40px}.input-otp-size-small.sc-ion-input-otp-ios-h .input-otp-group.sc-ion-input-otp-ios{gap:8px}.input-otp-size-medium.sc-ion-input-otp-ios-h{--width:48px;--height:48px}.input-otp-size-large.sc-ion-input-otp-ios-h{--width:56px;--height:56px}.input-otp-size-medium.sc-ion-input-otp-ios-h .input-otp-group.sc-ion-input-otp-ios,.input-otp-size-large.sc-ion-input-otp-ios-h .input-otp-group.sc-ion-input-otp-ios{gap:12px}.input-otp-shape-round.sc-ion-input-otp-ios-h{--border-radius:16px}.input-otp-shape-soft.sc-ion-input-otp-ios-h{--border-radius:8px}.input-otp-shape-rectangular.sc-ion-input-otp-ios-h{--border-radius:0}.input-otp-fill-outline.sc-ion-input-otp-ios-h{--background:none}.input-otp-fill-solid.sc-ion-input-otp-ios-h{--internal-border-color:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2));--background:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2))}.input-otp-disabled.sc-ion-input-otp-ios-h{--color:var(--ion-color-step-350, var(--ion-text-color-step-650, #a6a6a6))}.input-otp-fill-outline.input-otp-disabled.sc-ion-input-otp-ios-h{--background:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2));--internal-border-color:var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6))}.input-otp-disabled.sc-ion-input-otp-ios-h,.input-otp-disabled.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios:disabled{cursor:not-allowed}.has-focus.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios:focus{--border-color:var(--highlight-color);outline:none}.input-otp-fill-outline.input-otp-readonly.sc-ion-input-otp-ios-h{--background:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2))}.input-otp-fill-solid.input-otp-disabled.sc-ion-input-otp-ios-h,.input-otp-fill-solid.input-otp-readonly.sc-ion-input-otp-ios-h{--internal-border-color:var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6));--background:var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6))}.ion-touched.ion-invalid.sc-ion-input-otp-ios-h{--highlight-color:var(--highlight-color-invalid)}.ion-valid.sc-ion-input-otp-ios-h{--highlight-color:var(--highlight-color-valid)}.has-focus.ion-valid.sc-ion-input-otp-ios-h,.ion-touched.ion-invalid.sc-ion-input-otp-ios-h{--border-color:var(--highlight-color)}.ion-color.sc-ion-input-otp-ios-h{--highlight-color-focused:var(--ion-color-base)}.input-otp-fill-outline.ion-color.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios,.input-otp-fill-solid.ion-color.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios:focus{border-color:rgba(var(--ion-color-base-rgb), 0.6)}.input-otp-fill-outline.ion-color.ion-invalid.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios,.input-otp-fill-solid.ion-color.ion-invalid.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios,.input-otp-fill-outline.ion-color.has-focus.ion-invalid.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios,.input-otp-fill-solid.ion-color.has-focus.ion-invalid.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios{border-color:var(--ion-color-danger, #c5000f)}.input-otp-fill-outline.ion-color.ion-valid.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios,.input-otp-fill-solid.ion-color.ion-valid.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios,.input-otp-fill-outline.ion-color.has-focus.ion-valid.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios,.input-otp-fill-solid.ion-color.has-focus.ion-valid.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios{border-color:var(--ion-color-success, #2dd55b)}.input-otp-fill-outline.input-otp-disabled.ion-color.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios{border-color:rgba(var(--ion-color-base-rgb), 0.3)}.sc-ion-input-otp-ios-h{--border-width:0.55px}.has-focus.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios:focus{--border-width:1px}.input-otp-fill-outline.sc-ion-input-otp-ios-h{--internal-border-color:var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-250, var(--ion-background-color-step-250, #c8c7cc))))}`;
11
13
 
12
- const inputOtpMdCss = () => `.sc-ion-input-otp-md-h{--margin-top:0;--margin-end:0;--margin-bottom:0;--margin-start:0;--padding-top:16px;--padding-end:0;--padding-bottom:16px;--padding-start:0;--color:initial;--min-width:40px;--separator-width:8px;--separator-height:var(--separator-width);--separator-border-radius:999px;--separator-color:var(--ion-color-step-150, var(--ion-background-color-step-150, #d9d9d9));--highlight-color-focused:var(--ion-color-primary, #0054e9);--highlight-color-valid:var(--ion-color-success, #2dd55b);--highlight-color-invalid:var(--ion-color-danger, #c5000f);--highlight-color:var(--highlight-color-focused);display:block;position:relative;font-size:0.875rem}.input-otp-group.sc-ion-input-otp-md{-webkit-margin-start:var(--margin-start);margin-inline-start:var(--margin-start);-webkit-margin-end:var(--margin-end);margin-inline-end:var(--margin-end);margin-top:var(--margin-top);margin-bottom:var(--margin-bottom);-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.native-wrapper.sc-ion-input-otp-md{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;min-width:var(--min-width)}.native-input.sc-ion-input-otp-md{border-radius:var(--border-radius);width:var(--width);min-width:inherit;height:var(--height);border-width:var(--border-width);border-style:solid;border-color:var(--border-color);background:var(--background);color:var(--color);font-size:inherit;text-align:center;-webkit-appearance:none;-moz-appearance:none;appearance:none}.has-focus.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md{caret-color:var(--highlight-color)}.input-otp-description.sc-ion-input-otp-md{color:var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d));font-size:0.75rem;line-height:1.25rem;text-align:center}.input-otp-description-hidden.sc-ion-input-otp-md{display:none}.input-otp-separator.sc-ion-input-otp-md{border-radius:var(--separator-border-radius);-ms-flex-negative:0;flex-shrink:0;width:var(--separator-width);height:var(--separator-height);background:var(--separator-color)}.input-otp-size-small.sc-ion-input-otp-md-h{--width:40px;--height:40px}.input-otp-size-small.sc-ion-input-otp-md-h .input-otp-group.sc-ion-input-otp-md{gap:8px}.input-otp-size-medium.sc-ion-input-otp-md-h{--width:48px;--height:48px}.input-otp-size-large.sc-ion-input-otp-md-h{--width:56px;--height:56px}.input-otp-size-medium.sc-ion-input-otp-md-h .input-otp-group.sc-ion-input-otp-md,.input-otp-size-large.sc-ion-input-otp-md-h .input-otp-group.sc-ion-input-otp-md{gap:12px}.input-otp-shape-round.sc-ion-input-otp-md-h{--border-radius:16px}.input-otp-shape-soft.sc-ion-input-otp-md-h{--border-radius:8px}.input-otp-shape-rectangular.sc-ion-input-otp-md-h{--border-radius:0}.input-otp-fill-outline.sc-ion-input-otp-md-h{--background:none}.input-otp-fill-solid.sc-ion-input-otp-md-h{--border-color:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2));--background:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2))}.input-otp-disabled.sc-ion-input-otp-md-h{--color:var(--ion-color-step-350, var(--ion-text-color-step-650, #a6a6a6))}.input-otp-fill-outline.input-otp-disabled.sc-ion-input-otp-md-h{--background:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2));--border-color:var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6))}.input-otp-disabled.sc-ion-input-otp-md-h,.input-otp-disabled.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md:disabled{cursor:not-allowed}.has-focus.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md:focus{--border-color:var(--highlight-color);outline:none}.input-otp-fill-outline.input-otp-readonly.sc-ion-input-otp-md-h{--background:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2))}.input-otp-fill-solid.input-otp-disabled.sc-ion-input-otp-md-h,.input-otp-fill-solid.input-otp-readonly.sc-ion-input-otp-md-h{--border-color:var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6));--background:var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6))}.ion-touched.ion-invalid.sc-ion-input-otp-md-h{--highlight-color:var(--highlight-color-invalid)}.ion-valid.sc-ion-input-otp-md-h{--highlight-color:var(--highlight-color-valid)}.has-focus.ion-valid.sc-ion-input-otp-md-h,.ion-touched.ion-invalid.sc-ion-input-otp-md-h{--border-color:var(--highlight-color)}.ion-color.sc-ion-input-otp-md-h{--highlight-color-focused:var(--ion-color-base)}.input-otp-fill-outline.ion-color.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md,.input-otp-fill-solid.ion-color.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md:focus{border-color:rgba(var(--ion-color-base-rgb), 0.6)}.input-otp-fill-outline.ion-color.ion-invalid.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md,.input-otp-fill-solid.ion-color.ion-invalid.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md,.input-otp-fill-outline.ion-color.has-focus.ion-invalid.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md,.input-otp-fill-solid.ion-color.has-focus.ion-invalid.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md{border-color:var(--ion-color-danger, #c5000f)}.input-otp-fill-outline.ion-color.ion-valid.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md,.input-otp-fill-solid.ion-color.ion-valid.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md,.input-otp-fill-outline.ion-color.has-focus.ion-valid.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md,.input-otp-fill-solid.ion-color.has-focus.ion-valid.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md{border-color:var(--ion-color-success, #2dd55b)}.input-otp-fill-outline.input-otp-disabled.ion-color.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md{border-color:rgba(var(--ion-color-base-rgb), 0.3)}.sc-ion-input-otp-md-h{--border-width:1px}.has-focus.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md:focus{--border-width:2px}.input-otp-fill-outline.sc-ion-input-otp-md-h{--border-color:var(--ion-color-step-300, var(--ion-background-color-step-300, #b3b3b3))}`;
14
+ const inputOtpMdCss = () => `.sc-ion-input-otp-md-h{--margin-top:0;--margin-end:0;--margin-bottom:0;--margin-start:0;--padding-top:16px;--padding-end:0;--padding-bottom:16px;--padding-start:0;--color:initial;--min-width:40px;--separator-width:8px;--separator-height:var(--separator-width);--separator-border-radius:999px;--separator-color:var(--ion-color-step-150, var(--ion-background-color-step-150, #d9d9d9));--highlight-color-focused:var(--ion-color-primary, #0054e9);--highlight-color-valid:var(--ion-color-success, #2dd55b);--highlight-color-invalid:var(--ion-color-danger, #c5000f);--highlight-color:var(--highlight-color-focused);--border-color:initial;display:block;position:relative;font-size:0.875rem}.input-otp-group.sc-ion-input-otp-md{-webkit-margin-start:var(--margin-start);margin-inline-start:var(--margin-start);-webkit-margin-end:var(--margin-end);margin-inline-end:var(--margin-end);margin-top:var(--margin-top);margin-bottom:var(--margin-bottom);-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.native-wrapper.sc-ion-input-otp-md{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;min-width:var(--min-width)}.native-input.sc-ion-input-otp-md{border-radius:var(--border-radius);width:var(--width);min-width:inherit;height:var(--height);border-width:var(--border-width);border-style:solid;border-color:var(--border-color, var(--internal-border-color));background:var(--background);color:var(--color);font-size:inherit;text-align:center;-webkit-appearance:none;-moz-appearance:none;appearance:none}.has-focus.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md{caret-color:var(--highlight-color)}.input-otp-description.sc-ion-input-otp-md{color:var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d));font-size:0.75rem;line-height:1.25rem;text-align:center}.input-otp-description-hidden.sc-ion-input-otp-md{display:none}.input-otp-bottom.sc-ion-input-otp-md{font-size:0.75rem;line-height:1.25rem;text-align:center}.input-otp-bottom.sc-ion-input-otp-md .error-text.sc-ion-input-otp-md{display:none;color:var(--highlight-color-invalid)}.input-otp-bottom.sc-ion-input-otp-md .helper-text.sc-ion-input-otp-md{display:block;color:var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d))}.ion-touched.ion-invalid.sc-ion-input-otp-md-h .input-otp-bottom.sc-ion-input-otp-md .error-text.sc-ion-input-otp-md{display:block}.ion-touched.ion-invalid.sc-ion-input-otp-md-h .input-otp-bottom.sc-ion-input-otp-md .helper-text.sc-ion-input-otp-md{display:none}.input-otp-separator.sc-ion-input-otp-md{border-radius:var(--separator-border-radius);-ms-flex-negative:0;flex-shrink:0;width:var(--separator-width);height:var(--separator-height);background:var(--separator-color)}.input-otp-size-small.sc-ion-input-otp-md-h{--width:40px;--height:40px}.input-otp-size-small.sc-ion-input-otp-md-h .input-otp-group.sc-ion-input-otp-md{gap:8px}.input-otp-size-medium.sc-ion-input-otp-md-h{--width:48px;--height:48px}.input-otp-size-large.sc-ion-input-otp-md-h{--width:56px;--height:56px}.input-otp-size-medium.sc-ion-input-otp-md-h .input-otp-group.sc-ion-input-otp-md,.input-otp-size-large.sc-ion-input-otp-md-h .input-otp-group.sc-ion-input-otp-md{gap:12px}.input-otp-shape-round.sc-ion-input-otp-md-h{--border-radius:16px}.input-otp-shape-soft.sc-ion-input-otp-md-h{--border-radius:8px}.input-otp-shape-rectangular.sc-ion-input-otp-md-h{--border-radius:0}.input-otp-fill-outline.sc-ion-input-otp-md-h{--background:none}.input-otp-fill-solid.sc-ion-input-otp-md-h{--internal-border-color:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2));--background:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2))}.input-otp-disabled.sc-ion-input-otp-md-h{--color:var(--ion-color-step-350, var(--ion-text-color-step-650, #a6a6a6))}.input-otp-fill-outline.input-otp-disabled.sc-ion-input-otp-md-h{--background:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2));--internal-border-color:var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6))}.input-otp-disabled.sc-ion-input-otp-md-h,.input-otp-disabled.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md:disabled{cursor:not-allowed}.has-focus.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md:focus{--border-color:var(--highlight-color);outline:none}.input-otp-fill-outline.input-otp-readonly.sc-ion-input-otp-md-h{--background:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2))}.input-otp-fill-solid.input-otp-disabled.sc-ion-input-otp-md-h,.input-otp-fill-solid.input-otp-readonly.sc-ion-input-otp-md-h{--internal-border-color:var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6));--background:var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6))}.ion-touched.ion-invalid.sc-ion-input-otp-md-h{--highlight-color:var(--highlight-color-invalid)}.ion-valid.sc-ion-input-otp-md-h{--highlight-color:var(--highlight-color-valid)}.has-focus.ion-valid.sc-ion-input-otp-md-h,.ion-touched.ion-invalid.sc-ion-input-otp-md-h{--border-color:var(--highlight-color)}.ion-color.sc-ion-input-otp-md-h{--highlight-color-focused:var(--ion-color-base)}.input-otp-fill-outline.ion-color.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md,.input-otp-fill-solid.ion-color.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md:focus{border-color:rgba(var(--ion-color-base-rgb), 0.6)}.input-otp-fill-outline.ion-color.ion-invalid.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md,.input-otp-fill-solid.ion-color.ion-invalid.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md,.input-otp-fill-outline.ion-color.has-focus.ion-invalid.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md,.input-otp-fill-solid.ion-color.has-focus.ion-invalid.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md{border-color:var(--ion-color-danger, #c5000f)}.input-otp-fill-outline.ion-color.ion-valid.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md,.input-otp-fill-solid.ion-color.ion-valid.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md,.input-otp-fill-outline.ion-color.has-focus.ion-valid.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md,.input-otp-fill-solid.ion-color.has-focus.ion-valid.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md{border-color:var(--ion-color-success, #2dd55b)}.input-otp-fill-outline.input-otp-disabled.ion-color.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md{border-color:rgba(var(--ion-color-base-rgb), 0.3)}.sc-ion-input-otp-md-h{--border-width:1px}.has-focus.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md:focus{--border-width:2px}.input-otp-fill-outline.sc-ion-input-otp-md-h{--internal-border-color:var(--ion-color-step-300, var(--ion-background-color-step-300, #b3b3b3))}`;
13
15
 
14
16
  const InputOTP = class {
15
17
  constructor(hostRef) {
@@ -19,9 +21,11 @@ const InputOTP = class {
19
21
  this.ionComplete = createEvent(this, "ionComplete", 7);
20
22
  this.ionBlur = createEvent(this, "ionBlur", 7);
21
23
  this.ionFocus = createEvent(this, "ionFocus", 7);
22
- this.inheritedAttributes = {};
23
24
  this.inputRefs = [];
24
25
  this.inputId = `ion-input-otp-${inputIds++}`;
26
+ this.helperTextId = `${this.inputId}-helper-text`;
27
+ this.errorTextId = `${this.inputId}-error-text`;
28
+ this.descriptionId = `${this.inputId}-description`;
25
29
  this.parsedSeparators = [];
26
30
  /**
27
31
  * Tracks whether the user is navigating through input boxes using keyboard navigation
@@ -37,6 +41,7 @@ const InputOTP = class {
37
41
  this.inputValues = [];
38
42
  this.hasFocus = false;
39
43
  this.previousInputValues = [];
44
+ this.isInvalid = false;
40
45
  /**
41
46
  * Indicates whether and how the text value should be automatically capitalized as it is entered/edited by the user.
42
47
  * Available options: `"off"`, `"none"`, `"on"`, `"sentences"`, `"words"`, `"characters"`.
@@ -389,6 +394,10 @@ const InputOTP = class {
389
394
  this.inputRefs[tabbableIndex]?.focus();
390
395
  }
391
396
  }
397
+ // The host keeps these (see `HOST_ARIA_ATTRIBUTES`), so re-render when they change
398
+ onHostAriaChange() {
399
+ forceUpdate(this);
400
+ }
392
401
  valueChanged() {
393
402
  this.initializeValues();
394
403
  this.updateTabIndexes();
@@ -445,13 +454,45 @@ const InputOTP = class {
445
454
  }
446
455
  this.parsedSeparators = separatorValues.filter((pos) => pos <= length);
447
456
  }
457
+ connectedCallback() {
458
+ const { el } = this;
459
+ if (typeof MutationObserver !== 'undefined') {
460
+ this.validationObserver = new MutationObserver(() => {
461
+ const newIsInvalid = checkInvalidState(el);
462
+ if (this.isInvalid !== newIsInvalid) {
463
+ this.isInvalid = newIsInvalid;
464
+ // Force a re-render to update aria-describedby immediately
465
+ forceUpdate(this);
466
+ }
467
+ });
468
+ this.validationObserver.observe(el, {
469
+ attributes: true,
470
+ attributeFilter: ['class'],
471
+ });
472
+ }
473
+ this.isInvalid = checkInvalidState(el);
474
+ // Resumes watching after a move, since `componentWillLoad` only runs once
475
+ this.ariaController?.init();
476
+ }
477
+ disconnectedCallback() {
478
+ this.ariaController?.destroy();
479
+ if (this.validationObserver) {
480
+ this.validationObserver.disconnect();
481
+ this.validationObserver = undefined;
482
+ }
483
+ }
448
484
  componentWillLoad() {
449
- this.inheritedAttributes = inheritAriaAttributes(this.el);
485
+ // Only read `role` at load so a later host write isn't copied to the group
486
+ this.ariaController = createAttributeController(this.el, ariaAttributes.filter((attr) => !HOST_ARIA_ATTRIBUTES.includes(attr)), () => forceUpdate(this), ['role']);
450
487
  this.processSeparators();
451
488
  this.initializeValues();
452
489
  }
453
490
  componentDidLoad() {
454
491
  this.updateTabIndexes();
492
+ // The description only exists after the first render, so render again to reference it
493
+ if (this.getDescriptionText()) {
494
+ forceUpdate(this);
495
+ }
455
496
  }
456
497
  componentDidRender() {
457
498
  if (this.updateTabIndexesAfterRender) {
@@ -629,14 +670,77 @@ const InputOTP = class {
629
670
  const { length } = this;
630
671
  return this.parsedSeparators.includes(index + 1) && index < length - 1;
631
672
  }
673
+ /**
674
+ * Returns `undefined` until the first render creates the description container.
675
+ */
676
+ getDescriptionText() {
677
+ return this.el.querySelector('.input-otp-description')?.textContent?.trim();
678
+ }
679
+ getHintTextId() {
680
+ const { isInvalid, helperText, errorText, helperTextId, errorTextId } = this;
681
+ if (isInvalid && errorText) {
682
+ return errorTextId;
683
+ }
684
+ if (helperText) {
685
+ return helperTextId;
686
+ }
687
+ return undefined;
688
+ }
689
+ renderHintText() {
690
+ const { helperText, errorText, helperTextId, errorTextId, isInvalid } = this;
691
+ return [
692
+ h("div", { id: helperTextId, class: "helper-text", "aria-live": "polite" }, !isInvalid ? helperText : null),
693
+ h("div", { id: errorTextId, class: "error-text", role: "alert" }, isInvalid ? errorText : null),
694
+ ];
695
+ }
696
+ renderBottomContent() {
697
+ const { helperText, errorText } = this;
698
+ if (!helperText && !errorText) {
699
+ return;
700
+ }
701
+ return h("div", { class: "input-otp-bottom" }, this.renderHintText());
702
+ }
703
+ /**
704
+ * A custom formatter is used as is so translators control the whole name.
705
+ * With a host `aria-labelledby`, each box also references itself so its
706
+ * position is still read.
707
+ */
708
+ getInputLabelAttributes(index, hostAttributes) {
709
+ const { inputId, inputLabelFormatter, length } = this;
710
+ const hostLabel = hostAttributes['aria-label'];
711
+ const hostLabelledBy = hostAttributes['aria-labelledby'];
712
+ const position = `${index + 1} of ${length}`;
713
+ if (inputLabelFormatter !== undefined) {
714
+ try {
715
+ return { 'aria-label': inputLabelFormatter(index, length) };
716
+ }
717
+ catch (e) {
718
+ printIonError('[ion-input-otp] - Exception in provided `inputLabelFormatter`:', e);
719
+ }
720
+ }
721
+ if (hostLabelledBy) {
722
+ return { 'aria-label': position, 'aria-labelledby': `${hostLabelledBy} ${inputId}-${index}` };
723
+ }
724
+ return { 'aria-label': hostLabel ? `${hostLabel}, ${position}` : `Input ${position}` };
725
+ }
632
726
  render() {
633
- const { autocapitalize, color, disabled, el, fill, hasFocus, inheritedAttributes, inputId, inputRefs, inputValues, length, readonly, shape, size, } = this;
727
+ const { ariaController, autocapitalize, color, descriptionId, disabled, el, fill, hasFocus, inputId, inputRefs, inputValues, isInvalid, length, readonly, shape, size, } = this;
634
728
  const mode = getIonMode(this);
635
729
  const inputmode = this.getInputmode();
636
730
  const tabbableIndex = this.getTabbableIndex();
637
731
  const pattern = this.getPattern();
638
- const hasDescription = el.querySelector('.input-otp-description')?.textContent?.trim() !== '';
639
- return (h(Host, { key: 'def9fbd4fa135e6f435380c6ea86ac1621b4a111', class: createColorClasses(color, {
732
+ const descriptionText = this.getDescriptionText();
733
+ // Keep the description visible until the first render can check it
734
+ const hasDescription = descriptionText !== '';
735
+ /**
736
+ * Screen readers only announce these from the focused input. The
737
+ * description stays on the group so it isn't repeated for every input.
738
+ */
739
+ const { 'aria-errormessage': ariaErrorMessage, 'aria-required': ariaRequired, ...groupAttributes } = ariaController?.attributes ?? {};
740
+ const hostDescribedBy = el.getAttribute('aria-describedby');
741
+ const hostInvalid = el.getAttribute('aria-invalid') ?? undefined;
742
+ const describedBy = [hostDescribedBy, this.getHintTextId()].filter(Boolean).join(' ');
743
+ return (h(Host, { key: '5b13c3bed3979e269cf4409895954edb171d68f3', class: createColorClasses(color, {
640
744
  [mode]: true,
641
745
  'has-focus': hasFocus,
642
746
  [`input-otp-size-${size}`]: true,
@@ -644,7 +748,7 @@ const InputOTP = class {
644
748
  [`input-otp-fill-${fill}`]: true,
645
749
  'input-otp-disabled': disabled,
646
750
  'input-otp-readonly': readonly,
647
- }) }, h("div", { key: '5d3d7646a3d4fc856b7b2e1f53d29fca47b10baf', role: "group", "aria-label": "One-time password input", class: "input-otp-group", ...inheritedAttributes }, Array.from({ length }).map((_, index) => (h(Fragment, null, h("div", { class: "native-wrapper" }, h("input", { class: "native-input", id: `${inputId}-${index}`, "aria-label": `Input ${index + 1} of ${length}`, type: "text", autoCapitalize: autocapitalize, inputmode: inputmode, pattern: pattern, disabled: disabled, readOnly: readonly, tabIndex: index === tabbableIndex ? 0 : -1, value: inputValues[index] || '', autocomplete: "one-time-code", ref: (el) => {
751
+ }) }, h("div", { key: '6db010743f0eb5e059dc00de5822f117a264bb16', role: "group", class: "input-otp-group", ...groupAttributes, "aria-label": groupAttributes['aria-label'] || 'One-time password input', "aria-describedby": descriptionText ? descriptionId : undefined }, Array.from({ length }).map((_, index) => (h(Fragment, null, h("div", { class: "native-wrapper" }, h("input", { class: "native-input", id: `${inputId}-${index}`, ...this.getInputLabelAttributes(index, groupAttributes), "aria-describedby": describedBy || undefined, "aria-errormessage": ariaErrorMessage, "aria-invalid": isInvalid ? 'true' : hostInvalid, "aria-required": ariaRequired, type: "text", autoCapitalize: autocapitalize, inputmode: inputmode, pattern: pattern, disabled: disabled, readOnly: readonly, tabIndex: index === tabbableIndex ? 0 : -1, value: inputValues[index] || '', autocomplete: "one-time-code", ref: (el) => {
648
752
  if (el) {
649
753
  inputRefs[index] = el;
650
754
  }
@@ -652,13 +756,19 @@ const InputOTP = class {
652
756
  // The input was removed, so drop its ref and any after it.
653
757
  inputRefs.splice(index);
654
758
  }
655
- }, onInput: this.onInput(index), onBlur: this.onBlur, onFocus: this.onFocus(index), onKeyDown: this.onKeyDown(index), onPaste: this.onPaste })), this.showSeparator(index) && h("div", { class: "input-otp-separator" }))))), h("div", { key: '9d72a4ab35b5fdd6bba9701050c385ed253b310f', class: {
759
+ }, onInput: this.onInput(index), onBlur: this.onBlur, onFocus: this.onFocus(index), onKeyDown: this.onKeyDown(index), onPaste: this.onPaste })), this.showSeparator(index) && h("div", { class: "input-otp-separator" }))))), h("div", { key: '4d55d7532dcc28fadcb2f860dd2fcd2aa45ccccc', id: descriptionId, class: {
656
760
  'input-otp-description': true,
657
761
  'input-otp-description-hidden': !hasDescription,
658
- } }, h("slot", { key: '7deb3373c0d4e5deac22fa51577d271b9bb3a6d2' }))));
762
+ } }, h("slot", { key: '5d6823f48a9786799c9d485ce0d6b9de2ae7f537' })), this.renderBottomContent()));
659
763
  }
660
764
  get el() { return getElement(this); }
661
765
  static get watchers() { return {
766
+ "aria-describedby": [{
767
+ "onHostAriaChange": 0
768
+ }],
769
+ "aria-invalid": [{
770
+ "onHostAriaChange": 0
771
+ }],
662
772
  "value": [{
663
773
  "valueChanged": 0
664
774
  }],
@@ -673,6 +783,12 @@ const InputOTP = class {
673
783
  }; }
674
784
  };
675
785
  let inputIds = 0;
786
+ /**
787
+ * The attribute controller removes these from the host, so an app could never
788
+ * clear them. They stay on the host instead, which only works for global
789
+ * attributes since the host has no role.
790
+ */
791
+ const HOST_ARIA_ATTRIBUTES = ['aria-describedby', 'aria-invalid'];
676
792
  InputOTP.style = {
677
793
  ios: inputOtpIosCss(),
678
794
  md: inputOtpMdCss()
@@ -8,7 +8,7 @@ import { G as GESTURE_CONTROLLER } from './gesture-controller-B_gJaBk0.js';
8
8
  import { s as isEndSide, i as inheritAriaAttributes, l as assert, e as clamp } from './helpers-BJqKF1pr.js';
9
9
  import { m as menuController } from './index-DIouXecD.js';
10
10
  import { b as getIonMode, a as isPlatform } from './ionic-global-Cep6oYzK.js';
11
- import { h as hostContext, c as createColorClasses } from './theme-byZM6qHV.js';
11
+ import { c as createColorClasses, h as hostContext } from './theme-byZM6qHV.js';
12
12
  import { u as menuOutline, v as menuSharp } from './index-BvabGprD.js';
13
13
  import './framework-delegate-CDjM1vRH.js';
14
14
  import './dir-Dojwmvde.js';
@@ -172,7 +172,7 @@ const Menu = class {
172
172
  * of the split pane. If the split pane is
173
173
  * hidden then the menu should be too.
174
174
  */
175
- const splitPane = this.el.closest('ion-split-pane');
175
+ const splitPane = this.getSplitPane();
176
176
  if (splitPane !== null) {
177
177
  this.isPaneVisible = await splitPane.isVisible();
178
178
  }
@@ -211,8 +211,8 @@ const Menu = class {
211
211
  this.contentEl = undefined;
212
212
  }
213
213
  onSplitPaneChanged(ev) {
214
- const closestSplitPane = this.el.closest('ion-split-pane');
215
- if (closestSplitPane !== null && closestSplitPane === ev.target) {
214
+ const splitPane = this.getSplitPane();
215
+ if (splitPane !== null && splitPane === ev.target) {
216
216
  this.isPaneVisible = ev.detail.visible;
217
217
  this.updateState();
218
218
  }
@@ -410,6 +410,24 @@ const Menu = class {
410
410
  _isActive() {
411
411
  return !this.disabled && !this.isPaneVisible;
412
412
  }
413
+ /**
414
+ * Returns the split pane this menu is a side pane of.
415
+ * A menu inside the split pane's main content, such as one
416
+ * in a page, is a regular menu. The menu doesn't need to be
417
+ * a direct child, since it can be wrapped in a component.
418
+ */
419
+ getSplitPane() {
420
+ const splitPane = this.el.closest('ion-split-pane');
421
+ const main = this.el.closest('.split-pane-main');
422
+ /**
423
+ * A split pane can be the main content of an outer split
424
+ * pane, so only this split pane's main content counts.
425
+ */
426
+ if (splitPane === null || (main !== null && main !== splitPane && splitPane.contains(main))) {
427
+ return null;
428
+ }
429
+ return splitPane;
430
+ }
413
431
  canSwipe() {
414
432
  return this.swipeGesture && !this.isAnimating && this._isActive();
415
433
  }
@@ -653,21 +671,21 @@ const Menu = class {
653
671
  }
654
672
  }
655
673
  render() {
656
- const { type, disabled, el, isPaneVisible, inheritedAttributes, side } = this;
674
+ const { type, disabled, isPaneVisible, inheritedAttributes, side } = this;
657
675
  const mode = getIonMode(this);
658
676
  /**
659
677
  * If the Close Watcher is enabled then
660
678
  * the ionBackButton listener in the menu controller
661
679
  * will handle closing the menu when Escape is pressed.
662
680
  */
663
- return (h(Host, { key: '5cf26df26d4e539860cbeaea98ec621b98c3fcfc', onKeyDown: shouldUseCloseWatcher() ? null : this.onKeydown, role: "navigation", "aria-label": inheritedAttributes['aria-label'] || 'menu', class: {
681
+ return (h(Host, { key: '7481c8a32a135fb0fd6d5591eecbf3fb0a8e8dde', onKeyDown: shouldUseCloseWatcher() ? null : this.onKeydown, role: "navigation", "aria-label": inheritedAttributes['aria-label'] || 'menu', class: {
664
682
  [mode]: true,
665
683
  [`menu-type-${type}`]: true,
666
684
  'menu-enabled': !disabled,
667
685
  [`menu-side-${side}`]: true,
668
686
  'menu-pane-visible': isPaneVisible,
669
- 'split-pane-side': hostContext('ion-split-pane', el),
670
- } }, h("div", { key: 'f337016e293bb8665c99762e0c389dd6c372bb33', class: "menu-inner", part: "container", ref: (el) => (this.menuInnerEl = el) }, h("slot", { key: '4c3fe331aa42cd57d7ad9bd1f5910f8eeb62d7da' })), h("ion-backdrop", { key: '61af7ea876d81574841e1dd3e81e2352e555d096', ref: (el) => (this.backdropEl = el), class: "menu-backdrop", tappable: false, stopPropagation: false, part: "backdrop" })));
687
+ 'split-pane-side': this.getSplitPane() !== null,
688
+ } }, h("div", { key: '8ac2f0f531db944a46e5fef016d0b18bd7b804cc', class: "menu-inner", part: "container", ref: (el) => (this.menuInnerEl = el) }, h("slot", { key: '1ac3e13ccccf1adb7915b739fc794f2889b626ce' })), h("ion-backdrop", { key: 'f8becbf4de1a13feb57fb87973befecb88510bab', ref: (el) => (this.backdropEl = el), class: "menu-backdrop", tappable: false, stopPropagation: false, part: "backdrop" })));
671
689
  }
672
690
  get el() { return getElement(this); }
673
691
  static get watchers() { return {
@@ -17,6 +17,14 @@ const Route = class {
17
17
  *
18
18
  * Accepts paths similar to expressjs so that you can define parameters
19
19
  * in the url /foo/:bar where bar would be available in incoming props.
20
+ *
21
+ * A url ending in `*`, such as `*` or `/admin/*`, matches any remaining path,
22
+ * including none, so `/admin/*` also matches `/admin`. It only wins over a
23
+ * route that matches the whole path when it has more fixed segments, so
24
+ * `/admin/*` wins over `/:section/:id` but not over `/admin/:id`. It always
25
+ * wins over a route that matches by ignoring trailing segments, such as
26
+ * `/admin` for `/admin/users`. The matched path is passed in the `pathMatch`
27
+ * prop without a leading `/`. A `*` on a route with child routes is ignored.
20
28
  */
21
29
  this.url = '';
22
30
  }
@@ -80,6 +88,8 @@ const RouteRedirect = class {
80
88
  const ROUTER_INTENT_NONE = 'root';
81
89
  const ROUTER_INTENT_FORWARD = 'forward';
82
90
  const ROUTER_INTENT_BACK = 'back';
91
+ /** Param that holds the path matched by a trailing `*` in an `ion-route` url. */
92
+ const WILDCARD_PARAM = 'pathMatch';
83
93
 
84
94
  /** Join the non empty segments with "/". */
85
95
  const generatePath = (segments) => {
@@ -113,12 +123,13 @@ const writeSegments = (history, root, useHash, segments, direction, state, query
113
123
  *
114
124
  * Notes:
115
125
  * - parameter segments of the form :param are replaced with their value,
116
- * - null is returned when a value is missing for any parameter segment.
126
+ * - null is returned when a value is missing for any parameter segment,
127
+ * - a trailing wildcard is replaced with the path it matched.
117
128
  */
118
129
  const chainToSegments = (chain) => {
119
130
  const segments = [];
120
131
  for (const route of chain) {
121
- for (const segment of route.segments) {
132
+ for (const segment of withoutWildcard(route.segments)) {
122
133
  if (segment[0] === ':') {
123
134
  const param = route.params && route.params[segment.slice(1)];
124
135
  if (!param) {
@@ -130,9 +141,22 @@ const chainToSegments = (chain) => {
130
141
  segments.push(segment);
131
142
  }
132
143
  }
144
+ segments.push(...wildcardSegments(route));
133
145
  }
134
146
  return segments;
135
147
  };
148
+ /** Only a `*` in the last segment of a route url is a wildcard. Elsewhere it's matched literally. */
149
+ const endsWithWildcard = (segments) => {
150
+ return segments[segments.length - 1] === '*';
151
+ };
152
+ /** Returns the path segments matched by the trailing wildcard of the route. */
153
+ const wildcardSegments = (route) => {
154
+ const pathMatch = endsWithWildcard(route.segments) ? route.params?.[WILDCARD_PARAM] : undefined;
155
+ return pathMatch ? pathMatch.split('/').filter((s) => s.length > 0) : [];
156
+ };
157
+ const withoutWildcard = (segments) => {
158
+ return endsWithWildcard(segments) ? segments.slice(0, -1) : segments;
159
+ };
136
160
  /**
137
161
  * Removes the prefix segments from the path segments.
138
162
  *
@@ -465,6 +489,10 @@ const matchesIDs = (ids, chain) => {
465
489
  if (routeId.id.toLowerCase() !== routeChain.id) {
466
490
  break;
467
491
  }
492
+ // Weight a wildcard route when the outlet reports its `pathMatch`
493
+ if (routeId.params?.[WILDCARD_PARAM] !== undefined && endsWithWildcard(routeChain.segments)) {
494
+ score++;
495
+ }
468
496
  if (routeId.params) {
469
497
  const routeIdParams = Object.keys(routeId.params);
470
498
  // Only compare routes with the chain that have the same number of parameters.
@@ -520,21 +548,28 @@ const matchesSegments = (segments, chain) => {
520
548
  matchesDefault = true;
521
549
  }
522
550
  else {
523
- for (const segment of chainSegments) {
551
+ const params = {};
552
+ for (const segment of withoutWildcard(chainSegments)) {
524
553
  const data = inputSegments.next();
525
554
  // data param
526
555
  if (segment[0] === ':') {
527
556
  if (data === '') {
528
557
  return null;
529
558
  }
530
- allparams = allparams || [];
531
- const params = allparams[i] || (allparams[i] = {});
532
559
  params[segment.slice(1)] = data;
533
560
  }
534
561
  else if (data !== segment) {
535
562
  return null;
536
563
  }
537
564
  }
565
+ // A trailing `*` on a parent route has no effect. Its children match the rest of the path.
566
+ if (i === chain.length - 1 && endsWithWildcard(chainSegments)) {
567
+ params[WILDCARD_PARAM] = inputSegments.rest().join('/');
568
+ }
569
+ if (Object.keys(params).length > 0) {
570
+ allparams = allparams || [];
571
+ allparams[i] = params;
572
+ }
538
573
  matchesDefault = false;
539
574
  }
540
575
  }
@@ -566,25 +601,38 @@ const mergeParams = (a, b) => {
566
601
  * Returns the best match or null when no match is found.
567
602
  * When a chain is returned the parameters are updated from the RouteIDs.
568
603
  * That is they contain both the componentProps of the <ion-route> and the parameter segment.
604
+ *
605
+ * When a wildcard route ties with other routes, a route without a wildcard that can build a url wins,
606
+ * then the wildcard route. Otherwise the first route declared wins a tie.
569
607
  */
570
608
  const findChainForIDs = (ids, chains) => {
571
- let match = null;
572
609
  let maxMatches = 0;
610
+ let tied = [];
573
611
  for (const chain of chains) {
574
612
  const score = matchesIDs(ids, chain);
575
613
  if (score > maxMatches) {
576
- match = chain;
577
614
  maxMatches = score;
615
+ tied = [chain];
616
+ }
617
+ else if (score > 0 && score === maxMatches) {
618
+ tied.push(chain);
578
619
  }
579
620
  }
580
- if (match) {
581
- return match.map((route, i) => ({
582
- id: route.id,
583
- segments: route.segments,
584
- params: mergeParams(route.params, ids[i]?.params),
585
- }));
621
+ const matches = tied.map((chain) => chain.map((route, i) => ({
622
+ id: route.id,
623
+ segments: route.segments,
624
+ params: mergeParams(route.params, ids[i]?.params),
625
+ })));
626
+ if (!matches.some(chainEndsWithWildcard)) {
627
+ return matches.length > 0 ? matches[0] : null;
586
628
  }
587
- return null;
629
+ return matches.reduce((best, chain) => (tieRank(chain) > tieRank(best) ? chain : best));
630
+ };
631
+ const tieRank = (chain) => {
632
+ if (chainEndsWithWildcard(chain)) {
633
+ return 1;
634
+ }
635
+ return chainToSegments(chain) !== null ? 2 : 0;
588
636
  };
589
637
  /**
590
638
  * Finds the best match for the segments in the chains.
@@ -592,10 +640,17 @@ const findChainForIDs = (ids, chains) => {
592
640
  * Returns the best match or null when no match is found.
593
641
  * When a chain is returned the parameters are updated from the segments.
594
642
  * That is they contain both the componentProps of the <ion-route> and the parameter segments.
643
+ *
644
+ * When wildcard routes match, the one with the most fixed segments wins if it has more fixed segments than every
645
+ * route that matched the whole path. Routes that only matched by ignoring trailing segments don't count.
595
646
  */
596
647
  const findChainForSegments = (segments, chains) => {
597
648
  let match = null;
598
649
  let bestScore = 0;
650
+ let fullMatch = null;
651
+ let bestFullScore = 0;
652
+ let maxFullFixed = -1;
653
+ let wildcard = null;
599
654
  for (const chain of chains) {
600
655
  const matchedChain = matchesSegments(segments, chain);
601
656
  if (matchedChain !== null) {
@@ -604,9 +659,51 @@ const findChainForSegments = (segments, chains) => {
604
659
  bestScore = score;
605
660
  match = matchedChain;
606
661
  }
662
+ if (chainEndsWithWildcard(matchedChain)) {
663
+ if (wildcard === null || winsWildcard(matchedChain, wildcard)) {
664
+ wildcard = matchedChain;
665
+ }
666
+ }
667
+ else if (!isPartialMatch(segments, matchedChain)) {
668
+ if (score > bestFullScore) {
669
+ bestFullScore = score;
670
+ fullMatch = matchedChain;
671
+ }
672
+ maxFullFixed = Math.max(maxFullFixed, countFixedSegments(matchedChain));
673
+ }
674
+ }
675
+ }
676
+ // Without a wildcard to match the rest of the path, routes can still ignore trailing segments.
677
+ if (wildcard === null) {
678
+ return match;
679
+ }
680
+ // Compare fixed segments rather than priority, since nesting under default routes raises the priority
681
+ return countFixedSegments(wildcard) > maxFullFixed ? wildcard : fullMatch;
682
+ };
683
+ /** Returns whether the chain matched the path segments only by ignoring some trailing segments. */
684
+ const isPartialMatch = (segments, chain) => {
685
+ const matched = chainToSegments(chain);
686
+ return matched !== null && matched.length < segments.filter((s) => s !== '').length;
687
+ };
688
+ const chainEndsWithWildcard = (chain) => {
689
+ return endsWithWildcard(chain[chain.length - 1].segments);
690
+ };
691
+ /** Returns whether the wildcard chain beats `best` by fixed segments, then by priority. */
692
+ const winsWildcard = (chain, best) => {
693
+ const chainFixed = countFixedSegments(chain);
694
+ const bestFixed = countFixedSegments(best);
695
+ return chainFixed > bestFixed || (chainFixed === bestFixed && computePriority(chain) > computePriority(best));
696
+ };
697
+ const countFixedSegments = (chain) => {
698
+ let count = 0;
699
+ for (const route of chain) {
700
+ for (const segment of withoutWildcard(route.segments)) {
701
+ if (segment !== '' && segment[0] !== ':') {
702
+ count++;
703
+ }
607
704
  }
608
705
  }
609
- return match;
706
+ return count;
610
707
  };
611
708
  /**
612
709
  * Computes the priority of a chain.
@@ -618,12 +715,14 @@ const findChainForSegments = (segments, chains) => {
618
715
  * - /path/to/page
619
716
  *
620
717
  * The second one will be given a higher priority because "page" is a fixed segment (vs ":where", a parameter segment).
718
+ *
719
+ * A trailing wildcard is not counted.
621
720
  */
622
721
  const computePriority = (chain) => {
623
722
  let score = 1;
624
723
  let level = 1;
625
724
  for (const route of chain) {
626
- for (const segment of route.segments) {
725
+ for (const segment of withoutWildcard(route.segments)) {
627
726
  if (segment[0] === ':') {
628
727
  score += Math.pow(1, level);
629
728
  }
@@ -645,6 +744,12 @@ class RouterSegments {
645
744
  }
646
745
  return '';
647
746
  }
747
+ /** Consumes and returns the remaining non empty segments. */
748
+ rest() {
749
+ const rest = this.segments.filter((s) => s !== '');
750
+ this.segments = [];
751
+ return rest;
752
+ }
648
753
  }
649
754
 
650
755
  const readProp = (el, prop) => {