@ionic/core 9.0.3-dev.11788456135.1ab1d6cd → 9.0.3-dev.11790016799.1e269b7a

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 (183) hide show
  1. package/components/ion-accordion.js +1 -1
  2. package/components/ion-alert.js +1 -1
  3. package/components/ion-back-button.js +1 -1
  4. package/components/ion-breadcrumb.js +1 -1
  5. package/components/ion-checkbox.js +1 -1
  6. package/components/ion-datetime.js +1 -1
  7. package/components/ion-fab-button.js +1 -1
  8. package/components/ion-input-password-toggle.js +1 -1
  9. package/components/ion-input.js +1 -1
  10. package/components/ion-item.js +1 -1
  11. package/components/ion-menu-button.js +1 -1
  12. package/components/ion-refresher-content.js +1 -1
  13. package/components/ion-reorder.js +1 -1
  14. package/components/ion-searchbar.js +1 -1
  15. package/components/ion-select-modal.js +1 -1
  16. package/components/ion-select-popover.js +1 -1
  17. package/components/ion-select.js +1 -1
  18. package/components/ion-textarea.js +1 -1
  19. package/components/ion-toggle.js +1 -1
  20. package/components/{p-Cc3oC60a.js → p-0rXxxCTt.js} +1 -1
  21. package/components/p-B9ibhQu1.js +4 -0
  22. package/components/p-BzxHcuQH.js +4 -0
  23. package/components/p-C6wm_AQQ.js +4 -0
  24. package/components/p-CaxVJjmc.js +4 -0
  25. package/components/{p-Cm78Kk79.js → p-D2X-Hime.js} +1 -1
  26. package/css/ionic/bundle.ionic.css.map +1 -1
  27. package/css/ionic/core.ionic.css.map +1 -1
  28. package/css/ionic/global.bundle.ionic.css.map +1 -1
  29. package/css/ionic/ionic-swiper.ionic.css.map +1 -1
  30. package/css/ionic/link.ionic.css.map +1 -1
  31. package/css/ionic/typography.ionic.css.map +1 -1
  32. package/dist/cjs/ion-accordion_2.cjs.entry.js +9 -14
  33. package/dist/cjs/ion-alert.cjs.entry.js +4 -4
  34. package/dist/cjs/ion-back-button.cjs.entry.js +11 -13
  35. package/dist/cjs/ion-breadcrumb_2.cjs.entry.js +16 -29
  36. package/dist/cjs/ion-checkbox.cjs.entry.js +23 -15
  37. package/dist/cjs/ion-datetime.cjs.entry.js +14 -50
  38. package/dist/cjs/ion-fab_3.cjs.entry.js +9 -14
  39. package/dist/cjs/ion-input-password-toggle.cjs.entry.js +17 -29
  40. package/dist/cjs/ion-input.cjs.entry.js +12 -28
  41. package/dist/cjs/ion-item_8.cjs.entry.js +10 -15
  42. package/dist/cjs/ion-menu_3.cjs.entry.js +9 -12
  43. package/dist/cjs/ion-refresher_2.cjs.entry.js +10 -5
  44. package/dist/cjs/ion-reorder_2.cjs.entry.js +5 -13
  45. package/dist/cjs/ion-searchbar.cjs.entry.js +8 -37
  46. package/dist/cjs/ion-select-modal.cjs.entry.js +11 -10
  47. package/dist/cjs/ion-select_3.cjs.entry.js +13 -37
  48. package/dist/cjs/ion-textarea.cjs.entry.js +13 -21
  49. package/dist/cjs/ion-toggle.cjs.entry.js +12 -28
  50. package/dist/collection/components/accordion/accordion.js +9 -14
  51. package/dist/collection/components/alert/alert.ionic.css +7 -9
  52. package/dist/collection/components/alert/alert.js +3 -3
  53. package/dist/collection/components/back-button/back-button.js +11 -13
  54. package/dist/collection/components/breadcrumb/breadcrumb.js +16 -28
  55. package/dist/collection/components/checkbox/checkbox.ionic.css +35 -42
  56. package/dist/collection/components/checkbox/checkbox.ios.css +33 -29
  57. package/dist/collection/components/checkbox/checkbox.js +23 -13
  58. package/dist/collection/components/checkbox/checkbox.md.css +33 -29
  59. package/dist/collection/components/datetime/datetime.ios.css +5 -10
  60. package/dist/collection/components/datetime/datetime.js +12 -48
  61. package/dist/collection/components/datetime/datetime.md.css +5 -10
  62. package/dist/collection/components/fab-button/fab-button.js +9 -14
  63. package/dist/collection/components/input/input.ionic.css +102 -79
  64. package/dist/collection/components/input/input.js +11 -27
  65. package/dist/collection/components/input-password-toggle/input-password-toggle.js +18 -28
  66. package/dist/collection/components/item/item.js +10 -15
  67. package/dist/collection/components/menu-button/menu-button.js +9 -12
  68. package/dist/collection/components/refresher-content/refresher-content.js +10 -4
  69. package/dist/collection/components/reorder/reorder.js +5 -13
  70. package/dist/collection/components/searchbar/searchbar.js +8 -35
  71. package/dist/collection/components/select/select.ionic.css +187 -76
  72. package/dist/collection/components/select/select.js +14 -39
  73. package/dist/collection/components/select-modal/select-modal.js +12 -10
  74. package/dist/collection/components/textarea/textarea.ionic.css +133 -85
  75. package/dist/collection/components/textarea/textarea.ios.css +0 -4
  76. package/dist/collection/components/textarea/textarea.js +13 -18
  77. package/dist/collection/components/textarea/textarea.md.css +0 -4
  78. package/dist/collection/components/toggle/toggle.js +12 -26
  79. package/dist/collection/utils/test/playwright/field-geometry.js +34 -0
  80. package/dist/collection/utils/test/playwright/index.js +1 -0
  81. package/dist/docs.json +60 -25
  82. package/dist/esm/{index-BqQ15K9a.js → index-BkJpfpXI.js} +1 -1
  83. package/dist/esm/ion-accordion_2.entry.js +10 -15
  84. package/dist/esm/ion-alert.entry.js +4 -4
  85. package/dist/esm/ion-back-button.entry.js +12 -14
  86. package/dist/esm/ion-breadcrumb_2.entry.js +17 -30
  87. package/dist/esm/ion-checkbox.entry.js +24 -16
  88. package/dist/esm/ion-datetime.entry.js +15 -51
  89. package/dist/esm/ion-fab_3.entry.js +10 -15
  90. package/dist/esm/ion-input-password-toggle.entry.js +19 -31
  91. package/dist/esm/ion-input.entry.js +13 -29
  92. package/dist/esm/ion-item_8.entry.js +11 -16
  93. package/dist/esm/ion-menu_3.entry.js +10 -13
  94. package/dist/esm/ion-refresher_2.entry.js +11 -6
  95. package/dist/esm/ion-reorder_2.entry.js +6 -14
  96. package/dist/esm/ion-searchbar.entry.js +9 -38
  97. package/dist/esm/ion-select-modal.entry.js +13 -12
  98. package/dist/esm/ion-select_3.entry.js +14 -38
  99. package/dist/esm/ion-textarea.entry.js +13 -21
  100. package/dist/esm/ion-toggle.entry.js +13 -29
  101. package/dist/ionic/ionic.esm.js +1 -1
  102. package/dist/ionic/p-016f2ee0.entry.js +4 -0
  103. package/dist/ionic/p-07b95001.entry.js +4 -0
  104. package/dist/ionic/p-14dfe86e.entry.js +4 -0
  105. package/dist/ionic/p-167af5d6.entry.js +4 -0
  106. package/dist/ionic/p-18285aab.entry.js +4 -0
  107. package/dist/ionic/{p-2e3acd77.entry.js → p-1e0f0eb9.entry.js} +1 -1
  108. package/dist/ionic/p-368935f5.entry.js +4 -0
  109. package/dist/ionic/p-38da0794.entry.js +4 -0
  110. package/dist/ionic/p-80f71456.entry.js +4 -0
  111. package/dist/ionic/p-83aa4043.entry.js +4 -0
  112. package/dist/ionic/p-944ce631.entry.js +4 -0
  113. package/dist/ionic/{p-BqQ15K9a.js → p-BkJpfpXI.js} +1 -1
  114. package/dist/ionic/p-aecef1d7.entry.js +4 -0
  115. package/dist/ionic/p-bb83b861.entry.js +4 -0
  116. package/dist/ionic/p-c1c90068.entry.js +4 -0
  117. package/dist/ionic/p-ccc7487b.entry.js +4 -0
  118. package/dist/ionic/p-cfd5dc50.entry.js +4 -0
  119. package/dist/ionic/p-d5c9bf12.entry.js +4 -0
  120. package/dist/ionic/p-f252ab8a.entry.js +4 -0
  121. package/dist/types/components/accordion/accordion.d.ts +7 -1
  122. package/dist/types/components/back-button/back-button.d.ts +8 -2
  123. package/dist/types/components/breadcrumb/breadcrumb.d.ts +12 -2
  124. package/dist/types/components/checkbox/checkbox.d.ts +12 -1
  125. package/dist/types/components/datetime/datetime.d.ts +4 -4
  126. package/dist/types/components/fab-button/fab-button.d.ts +7 -1
  127. package/dist/types/components/input/input.d.ts +7 -10
  128. package/dist/types/components/input-password-toggle/input-password-toggle.d.ts +14 -2
  129. package/dist/types/components/item/item.d.ts +7 -1
  130. package/dist/types/components/menu-button/menu-button.d.ts +6 -1
  131. package/dist/types/components/refresher-content/refresher-content.d.ts +6 -0
  132. package/dist/types/components/reorder/reorder.d.ts +1 -1
  133. package/dist/types/components/select/select.d.ts +7 -12
  134. package/dist/types/components/select-modal/select-modal.d.ts +6 -1
  135. package/dist/types/components/textarea/textarea.d.ts +8 -8
  136. package/dist/types/components/toggle/toggle.d.ts +5 -2
  137. package/dist/types/utils/config.d.ts +22 -2
  138. package/dist/types/utils/test/playwright/field-geometry.d.ts +13 -0
  139. package/dist/types/utils/test/playwright/index.d.ts +1 -0
  140. package/hydrate/index.js +213 -375
  141. package/hydrate/index.mjs +213 -375
  142. package/package.json +1 -2
  143. package/components/p-B1AK6oR-.js +0 -4
  144. package/components/p-BDqjX7Z_.js +0 -4
  145. package/components/p-BYSs-jZz.js +0 -4
  146. package/components/p-CPdOdJa7.js +0 -4
  147. package/components/p-D1t981Ih.js +0 -4
  148. package/components/p-Dhi5xtNS.js +0 -4
  149. package/components/p-DzaPYdjZ.js +0 -4
  150. package/components/p-e73ca-aN.js +0 -4
  151. package/components/p-fIOYmaqA.js +0 -4
  152. package/dist/cjs/caret-down-vtVgfXIs.js +0 -8
  153. package/dist/cjs/caret-left-CxZXLRv5.js +0 -8
  154. package/dist/cjs/caret-right-CRCgv98E.js +0 -8
  155. package/dist/cjs/list-a-7GSA6K.js +0 -8
  156. package/dist/cjs/x-BTF99yFH.js +0 -8
  157. package/dist/esm/caret-down-D1t981Ih.js +0 -6
  158. package/dist/esm/caret-left-fIOYmaqA.js +0 -6
  159. package/dist/esm/caret-right-BYSs-jZz.js +0 -6
  160. package/dist/esm/list-Dhi5xtNS.js +0 -6
  161. package/dist/esm/x-BDqjX7Z_.js +0 -6
  162. package/dist/ionic/p-04d96dad.entry.js +0 -4
  163. package/dist/ionic/p-0a924e6a.entry.js +0 -4
  164. package/dist/ionic/p-2da21af7.entry.js +0 -4
  165. package/dist/ionic/p-2fc1521f.entry.js +0 -4
  166. package/dist/ionic/p-73309d35.entry.js +0 -4
  167. package/dist/ionic/p-74ab5f49.entry.js +0 -4
  168. package/dist/ionic/p-83d13d56.entry.js +0 -4
  169. package/dist/ionic/p-8dcd18cf.entry.js +0 -4
  170. package/dist/ionic/p-9ca59419.entry.js +0 -4
  171. package/dist/ionic/p-BDqjX7Z_.js +0 -4
  172. package/dist/ionic/p-BYSs-jZz.js +0 -4
  173. package/dist/ionic/p-D1t981Ih.js +0 -4
  174. package/dist/ionic/p-Dhi5xtNS.js +0 -4
  175. package/dist/ionic/p-b10dc124.entry.js +0 -4
  176. package/dist/ionic/p-b7ce4a50.entry.js +0 -4
  177. package/dist/ionic/p-c7035f3f.entry.js +0 -4
  178. package/dist/ionic/p-c91fc9d4.entry.js +0 -4
  179. package/dist/ionic/p-cd4791d5.entry.js +0 -4
  180. package/dist/ionic/p-e9480e7f.entry.js +0 -4
  181. package/dist/ionic/p-e9fdff49.entry.js +0 -4
  182. package/dist/ionic/p-f82b13a6.entry.js +0 -4
  183. package/dist/ionic/p-fIOYmaqA.js +0 -4
@@ -1,9 +1,6 @@
1
1
  /*!
2
2
  * (C) Ionic http://ionicframework.com - MIT License
3
3
  */
4
- import arrowLeftRegular from "@phosphor-icons/core/assets/regular/arrow-left.svg";
5
- import magnifyingGlassRegular from "@phosphor-icons/core/assets/regular/magnifying-glass.svg";
6
- import xRegular from "@phosphor-icons/core/assets/regular/x.svg";
7
4
  import { Host, forceUpdate, h } from "@stencil/core";
8
5
  import { createClearButtonPressController } from "../../utils/forms/index";
9
6
  import { debounceEvent, raf, componentOnReady, inheritAttributes } from "../../utils/helpers";
@@ -510,16 +507,9 @@ export class Searchbar {
510
507
  if (this.clearIcon != null) {
511
508
  return this.clearIcon;
512
509
  }
513
- // Determine the theme and map to default icons
510
+ // Determine the theme and map to the default icon
514
511
  const theme = getIonTheme(this);
515
- const defaultIcons = {
516
- ios: closeCircle,
517
- ionic: xRegular,
518
- md: closeSharp,
519
- };
520
- // Get the default icon based on the theme, falling back to 'md' icon if necessary
521
- const defaultIcon = defaultIcons[theme] || defaultIcons.md;
522
- // Return the configured searchbar clear icon or the default icon
512
+ const defaultIcon = theme === 'ios' ? closeCircle : closeSharp;
523
513
  return config.get('searchbarClearIcon', defaultIcon);
524
514
  }
525
515
  /**
@@ -534,16 +524,9 @@ export class Searchbar {
534
524
  if (this.searchIcon != null && this.searchIcon !== 'true' && typeof this.searchIcon !== 'boolean') {
535
525
  return this.searchIcon;
536
526
  }
537
- // Determine the theme and map to default icons
527
+ // Determine the theme and map to the default icon
538
528
  const theme = getIonTheme(this);
539
- const defaultIcons = {
540
- ios: searchOutline,
541
- ionic: magnifyingGlassRegular,
542
- md: searchSharp,
543
- };
544
- // Get the default icon based on the theme, falling back to 'md' icon if necessary
545
- const defaultIcon = defaultIcons[theme] || defaultIcons.md;
546
- // Return the configured searchbar search icon or the default icon
529
+ const defaultIcon = theme === 'ios' ? searchOutline : searchSharp;
547
530
  return config.get('searchbarSearchIcon', defaultIcon);
548
531
  }
549
532
  /**
@@ -557,17 +540,7 @@ export class Searchbar {
557
540
  if (this.cancelButtonIcon != null) {
558
541
  return this.cancelButtonIcon;
559
542
  }
560
- // Determine the theme and map to default icons
561
- const theme = getIonTheme(this);
562
- const defaultIcons = {
563
- ios: arrowBackSharp,
564
- ionic: arrowLeftRegular,
565
- md: arrowBackSharp,
566
- };
567
- // Get the default icon based on the theme, falling back to 'md' icon if necessary
568
- const defaultIcon = defaultIcons[theme] || defaultIcons.md;
569
- // Return the configured searchbar cancel icon, the back button icon or the default icon
570
- return config.get('searchbarCancelIcon', config.get('backButtonIcon', defaultIcon));
543
+ return config.get('searchbarCancelIcon', config.get('backButtonIcon', arrowBackSharp));
571
544
  }
572
545
  render() {
573
546
  const { cancelButtonText, autocapitalize, searchbarCancelIcon, searchbarClearIcon, searchbarSearchIcon } = this;
@@ -576,8 +549,8 @@ export class Searchbar {
576
549
  const shouldShowCancelButton = this.shouldShowCancelButton();
577
550
  const shape = this.getShape();
578
551
  const size = this.getSize();
579
- const cancelButton = this.showCancelButton !== 'never' && (h("button", { key: 'b573b41a2e7e53c7001d4449bb8479a139b2ae59', "aria-label": cancelButtonText, "aria-hidden": shouldShowCancelButton ? undefined : 'true', type: "button", tabIndex: theme === 'ios' && !shouldShowCancelButton ? -1 : undefined, onMouseDown: this.onCancelSearchbar, onTouchStart: this.onCancelSearchbar, class: "searchbar-cancel-button" }, h("div", { key: 'f87afde3e0e96e9af4abf08396df2e9cc13c69bc', "aria-hidden": "true" }, theme === 'md' || theme === 'ionic' ? (h("ion-icon", { "aria-hidden": "true", icon: searchbarCancelIcon, lazy: false })) : (cancelButtonText))));
580
- return (h(Host, { key: 'cee57a4aec582e6e42a4bda5ba0f4011255a5a90', role: "search", "aria-disabled": this.disabled ? 'true' : null, class: createColorClasses(this.color, {
552
+ const cancelButton = this.showCancelButton !== 'never' && (h("button", { key: '21118a391a384643863018f787ffc36b1b81ba90', "aria-label": cancelButtonText, "aria-hidden": shouldShowCancelButton ? undefined : 'true', type: "button", tabIndex: theme === 'ios' && !shouldShowCancelButton ? -1 : undefined, onMouseDown: this.onCancelSearchbar, onTouchStart: this.onCancelSearchbar, class: "searchbar-cancel-button" }, h("div", { key: 'b59db009ec11b82479c18f29f6df30121ad2a795', "aria-hidden": "true" }, theme === 'md' || theme === 'ionic' ? (h("ion-icon", { "aria-hidden": "true", icon: searchbarCancelIcon, lazy: false })) : (cancelButtonText))));
553
+ return (h(Host, { key: '5732dd17714bd1f11ac2d8c39853347944aa61cf', role: "search", "aria-disabled": this.disabled ? 'true' : null, class: createColorClasses(this.color, {
581
554
  [theme]: true,
582
555
  'searchbar-animated': animated,
583
556
  'searchbar-disabled': this.disabled,
@@ -591,7 +564,7 @@ export class Searchbar {
591
564
  [`searchbar-shape-${shape}`]: shape !== undefined,
592
565
  [`searchbar-size-${size}`]: size !== undefined,
593
566
  'in-toolbar': hostContext('ion-toolbar', this.el),
594
- }) }, h("div", { key: '277b419e792c484ae0aadb3703118bd7f4d281f6', class: "searchbar-input-container" }, h("input", { key: 'abf94e0496dde1953a928fd50c1ab6f1290e84c5', "aria-label": "search text", disabled: this.disabled, ref: (el) => (this.nativeInput = el), class: "searchbar-input", inputMode: this.inputmode, enterKeyHint: this.enterkeyhint, name: this.name, onInput: this.onInput, onChange: this.onChange, onBlur: this.onBlur, onFocus: this.onFocus, minLength: this.minlength, maxLength: this.maxlength, placeholder: this.placeholder, type: this.type, value: this.getValue(), autoCapitalize: autocapitalize === 'default' ? undefined : autocapitalize, autoComplete: this.autocomplete, autoCorrect: this.autocorrect ? 'on' : 'off', spellcheck: this.spellcheck, ...this.inheritedAttributes }), (theme === 'md' || theme === 'ionic') && cancelButton, this.shouldShowSearchIcon() && (h("ion-icon", { key: '12fb162dd40f3222bf8b0bd6fa7cf8f839be30f8', "aria-hidden": "true", icon: searchbarSearchIcon, lazy: false, class: "searchbar-search-icon" })), this.shouldShowClearButton() && (h("button", { key: 'ecc08e7514cf92e7f8cda780cb50c5f27c5d7966', "aria-label": "reset", type: "button", "no-blur": true, class: "searchbar-clear-button", onPointerDown: this.clearButtonPressController.onPointerDown, onPointerCancel: this.clearButtonPressController.release, onClick: () => this.onClearInput(true) }, h("ion-icon", { key: 'de6c375fe60d4d3f9ed10dd5fa08ed11685cb4fa', "aria-hidden": "true", icon: searchbarClearIcon, lazy: false, class: "searchbar-clear-icon" })))), theme === 'ios' && cancelButton));
567
+ }) }, h("div", { key: '024e67b33903cf73f057edeb4cb8f58b6d787e11', class: "searchbar-input-container" }, h("input", { key: 'f10260bbff84cc549ec312e9cb763e85641d83c6', "aria-label": "search text", disabled: this.disabled, ref: (el) => (this.nativeInput = el), class: "searchbar-input", inputMode: this.inputmode, enterKeyHint: this.enterkeyhint, name: this.name, onInput: this.onInput, onChange: this.onChange, onBlur: this.onBlur, onFocus: this.onFocus, minLength: this.minlength, maxLength: this.maxlength, placeholder: this.placeholder, type: this.type, value: this.getValue(), autoCapitalize: autocapitalize === 'default' ? undefined : autocapitalize, autoComplete: this.autocomplete, autoCorrect: this.autocorrect ? 'on' : 'off', spellcheck: this.spellcheck, ...this.inheritedAttributes }), (theme === 'md' || theme === 'ionic') && cancelButton, this.shouldShowSearchIcon() && (h("ion-icon", { key: '513780a9904403d85fb9074f13d6c3f2187ddb56', "aria-hidden": "true", icon: searchbarSearchIcon, lazy: false, class: "searchbar-search-icon" })), this.shouldShowClearButton() && (h("button", { key: 'dd25c5e940a6cea07e6be028e83808e91eb2f4eb', "aria-label": "reset", type: "button", "no-blur": true, class: "searchbar-clear-button", onPointerDown: this.clearButtonPressController.onPointerDown, onPointerCancel: this.clearButtonPressController.release, onClick: () => this.onClearInput(true) }, h("ion-icon", { key: '8a1163ccb8aa63a6596ae160f10d619ff162caef', "aria-hidden": "true", icon: searchbarClearIcon, lazy: false, class: "searchbar-clear-icon" })))), theme === 'ios' && cancelButton));
595
568
  }
596
569
  static get is() { return "ion-searchbar"; }
597
570
  static get encapsulation() { return "scoped"; }
@@ -534,41 +534,8 @@ button {
534
534
  border-top: none;
535
535
  }
536
536
 
537
- :host(.select-fill-outline) .label-text-wrapper {
538
- /**
539
- * The label should appear on top of an outline
540
- * container that overlaps it so it is always clickable.
541
- */
542
- position: relative;
543
- }
544
-
545
- :host(.select-fill-outline) .select-wrapper-inner {
546
- border-radius: var(--border-radius);
547
- -webkit-padding-start: var(--padding-start);
548
- padding-inline-start: var(--padding-start);
549
- -webkit-padding-end: var(--padding-end);
550
- padding-inline-end: var(--padding-end);
551
- padding-top: var(--padding-top);
552
- padding-bottom: var(--padding-bottom);
553
- /**
554
- * Apply the background to the native select
555
- * wrapper to only style the select.
556
- */
557
- background: var(--background);
558
- }
559
-
560
- :host(.select-fill-outline) .select-outline {
561
- right: 0;
562
- left: 0;
563
- top: 0;
564
- bottom: 0;
565
- border-radius: var(--border-radius);
566
- position: absolute;
567
- width: 100%;
568
- height: 100%;
569
- pointer-events: none;
537
+ :host(.select-fill-outline) .select-wrapper::before {
570
538
  border: var(--border-width) var(--border-style) var(--border-color);
571
- box-sizing: border-box;
572
539
  }
573
540
 
574
541
  :host(.ion-focused.select-fill-outline) {
@@ -668,7 +635,6 @@ button {
668
635
  }
669
636
 
670
637
  :host(.select-label-placement-fixed) .label-text-wrapper {
671
- flex: 0 0 calc(var(--token-scale-2400, 96px) + var(--token-space-100, var(--token-scale-100, 4px)));
672
638
  width: calc(var(--token-scale-2400, 96px) + var(--token-space-100, var(--token-scale-100, 4px)));
673
639
  min-width: calc(var(--token-scale-2400, 96px) + var(--token-space-100, var(--token-scale-100, 4px)));
674
640
  max-width: var(--token-scale-5000, 200px);
@@ -701,46 +667,201 @@ button {
701
667
  margin-bottom: var(--token-space-100, var(--token-scale-100, 4px));
702
668
  }
703
669
 
670
+ /**
671
+ * The label is nested in the control so that every theme renders the same
672
+ * tree. Laying the wrapper out as a grid and flattening the control lets the
673
+ * label sit outside the field box, which is drawn by `::before` over the cells
674
+ * the label does not occupy.
675
+ */
704
676
  .select-wrapper {
677
+ display: grid;
678
+ /**
679
+ * Only stretch grows an auto row, so centering holds the label row at its
680
+ * content height and still centers the field in any leftover host height.
681
+ */
682
+ align-content: center;
705
683
  align-items: center;
706
684
  min-width: var(--token-scale-5000, 200px);
707
685
  background: transparent;
708
686
  }
709
687
 
688
+ .select-control {
689
+ display: contents;
690
+ }
691
+
692
+ /**
693
+ * A pseudo-element draws the box over the field cells, so the label stays
694
+ * outside of it.
695
+ */
696
+ .select-wrapper::before {
697
+ border-radius: var(--border-radius, 0);
698
+ align-self: stretch;
699
+ box-sizing: border-box;
700
+ content: "";
701
+ pointer-events: none;
702
+ background: var(--background);
703
+ }
704
+
705
+ /**
706
+ * The field row is as tall as the size asks for, whatever the slots contain.
707
+ */
708
+ :host(.select-size-small) .select-wrapper {
709
+ --internal-field-height: var(--token-scale-1000, 40px);
710
+ }
711
+
712
+ :host(.select-size-medium) .select-wrapper {
713
+ --internal-field-height: var(--token-scale-1200, 48px);
714
+ }
715
+
716
+ :host(.select-size-large) .select-wrapper {
717
+ --internal-field-height: var(--token-scale-1400, 56px);
718
+ }
719
+
720
+ :host(.select-label-placement-start) .label-text-wrapper,
721
+ :host(.select-label-placement-fixed) .label-text-wrapper,
722
+ :host(.select-label-placement-end) .label-text-wrapper {
723
+ grid-column: label;
724
+ }
725
+
726
+ :host(.select-label-placement-stacked) .label-text-wrapper,
727
+ :host(.select-label-placement-floating) .label-text-wrapper {
728
+ grid-column: field-start/field-end;
729
+ }
730
+
731
+ /**
732
+ * The `justify-content` property cannot serve here the way it does on a flex
733
+ * row, because grid would distribute the free space between every track,
734
+ * including the ones inside the field. So three empty tracks stand in for that
735
+ * space, and the justify property below decides which of them takes it. The
736
+ * other two collapse to `0fr`.
737
+ */
738
+ :host(.select-label-placement-start) .select-wrapper,
739
+ :host(.select-label-placement-fixed) .select-wrapper {
740
+ grid-template-columns: var(--internal-justify-lead, 0fr) [label] auto var(--internal-justify-gap, 1fr) [field-start slot-start] minmax(0, auto) [native] minmax(0, auto) [slot-end] minmax(0, auto) [field-end] var(--internal-justify-trail, 0fr);
741
+ grid-template-rows: [label field] var(--internal-field-height, auto);
742
+ }
743
+
744
+ :host(.select-label-placement-end) .select-wrapper {
745
+ grid-template-columns: var(--internal-justify-lead, 0fr) [field-start slot-start] minmax(0, auto) [native] minmax(0, auto) [slot-end] minmax(0, auto) [field-end] var(--internal-justify-gap, 1fr) [label] auto var(--internal-justify-trail, 0fr);
746
+ grid-template-rows: [label field] var(--internal-field-height, auto);
747
+ }
748
+
749
+ /**
750
+ * With no label there is nothing to separate the field from, so the free space
751
+ * belongs after the field instead of before it. The label's own track collapses
752
+ * on its own, but the flexible one does not.
753
+ */
754
+ :host(:not(.has-label)) .select-wrapper {
755
+ --internal-justify-gap: 0fr;
756
+ --internal-justify-trail: 1fr;
757
+ }
758
+
759
+ /**
760
+ * Each of these declares all three tracks. Declaring only the ones it moves
761
+ * would leave the others at whatever the no-label rule above set, since the
762
+ * cascade resolves per declaration and the two rules have equal specificity.
763
+ *
764
+ * Exactly one track stays flexible in every combination. That leaves no free
765
+ * space for the `justify-content` the shared stylesheet sets on the wrapper, so
766
+ * it stays inert. Leave all three at `0fr` and it starts distributing space
767
+ * between the field's own tracks.
768
+ */
769
+ :host(.select-justify-start) .select-wrapper {
770
+ --internal-justify-lead: 0fr;
771
+ --internal-justify-gap: 0fr;
772
+ --internal-justify-trail: 1fr;
773
+ }
774
+
775
+ :host(.select-justify-end) .select-wrapper {
776
+ --internal-justify-lead: 1fr;
777
+ --internal-justify-gap: 0fr;
778
+ --internal-justify-trail: 0fr;
779
+ }
780
+
781
+ /**
782
+ * This only applies with a label, because `space-between` on a flex row with one
783
+ * in-flow item behaves as start, which is what the no-label rule already gives.
784
+ */
785
+ :host(.has-label.select-justify-space-between) .select-wrapper {
786
+ --internal-justify-lead: 0fr;
787
+ --internal-justify-gap: 1fr;
788
+ --internal-justify-trail: 0fr;
789
+ }
790
+
710
791
  :host(.select-label-placement-stacked) .select-wrapper,
711
792
  :host(.select-label-placement-floating) .select-wrapper {
712
- flex-direction: column;
713
- align-items: start;
793
+ grid-template-columns: [field-start slot-start] minmax(0, auto) [native] minmax(0, 1fr) [slot-end] minmax(0, auto) [field-end];
794
+ grid-template-rows: [label] auto [field] var(--internal-field-height, auto);
714
795
  }
715
796
 
716
- .select-wrapper .select-placeholder {
717
- /**
718
- * When the floating label appears on top of the
719
- * select, we need to fade the text out so that the
720
- * label does not overlap with the placeholder.
721
- */
722
- transition: opacity var(--token-transition-time-150, 150ms) var(--token-transition-curve-expressive, cubic-bezier(0.4, 0, 0.2, 1));
797
+ /**
798
+ * The templates above all name the same lines, so every placement shares these.
799
+ * A label with its own row lands on the label row. Otherwise that name resolves
800
+ * to the only row there is.
801
+ */
802
+ .label-text-wrapper {
803
+ grid-row: label;
804
+ }
805
+
806
+ .select-start {
807
+ grid-row: field;
808
+ grid-column: slot-start;
723
809
  }
724
810
 
725
- .select-wrapper-inner {
726
- border-radius: var(--border-radius);
811
+ .native-wrapper {
812
+ grid-row: field;
813
+ grid-column: native;
814
+ }
815
+
816
+ .select-end {
817
+ grid-row: field;
818
+ grid-column: slot-end;
819
+ }
820
+
821
+ .select-wrapper::before {
822
+ grid-row: field;
823
+ grid-column: field-start/field-end;
824
+ }
825
+
826
+ /**
827
+ * The padding sits on the cells that the field box covers, so the label is not
828
+ * indented by it.
829
+ */
830
+ .select-start {
727
831
  -webkit-padding-start: var(--padding-start);
728
832
  padding-inline-start: var(--padding-start);
833
+ padding-top: var(--padding-top);
834
+ padding-bottom: var(--padding-bottom);
835
+ }
836
+
837
+ .native-wrapper {
838
+ padding-top: var(--padding-top);
839
+ padding-bottom: var(--padding-bottom);
840
+ }
841
+
842
+ .select-end {
729
843
  -webkit-padding-end: var(--padding-end);
730
844
  padding-inline-end: var(--padding-end);
731
845
  padding-top: var(--padding-top);
732
846
  padding-bottom: var(--padding-bottom);
733
- display: flex;
734
- position: relative;
735
- align-items: center;
736
- background: var(--background);
737
- box-sizing: border-box;
847
+ }
848
+
849
+ /**
850
+ * The slot cells can shrink below their content so that oversized slotted
851
+ * content is cut off at the edge of the field instead of widening it.
852
+ */
853
+ .select-start,
854
+ .select-end {
738
855
  overflow: hidden;
739
856
  }
740
857
 
741
- :host(.select-label-placement-stacked) .select-wrapper-inner,
742
- :host(.select-label-placement-floating) .select-wrapper-inner {
743
- width: 100%;
858
+ .select-wrapper .select-placeholder {
859
+ /**
860
+ * When the floating label appears on top of the
861
+ * select, we need to fade the text out so that the
862
+ * label does not overlap with the placeholder.
863
+ */
864
+ transition: opacity var(--token-transition-time-150, 150ms) var(--token-transition-curve-expressive, cubic-bezier(0.4, 0, 0.2, 1));
744
865
  }
745
866
 
746
867
  .native-wrapper {
@@ -759,16 +880,6 @@ button {
759
880
  color: var(--token-text-default, var(--token-primitives-neutral-1200, #242424));
760
881
  }
761
882
 
762
- :host(.select-label-placement-stacked) .native-wrapper,
763
- :host(.select-label-placement-floating) .native-wrapper {
764
- /**
765
- * Text should not extend beyond the bounds of the select.
766
- * This is done by setting the width to the full width minus
767
- * the icon width and the gap between the icon and the text.
768
- */
769
- width: calc(100% - var(--token-scale-400, 16px) - var(--token-space-200, var(--token-scale-200, 8px)));
770
- }
771
-
772
883
  /**
773
884
  * Slotted buttons have a lot of default padding that can
774
885
  * cause them to look misaligned from other pieces such
@@ -811,6 +922,18 @@ button {
811
922
  color: var(--token-text-subtlest, var(--token-primitives-neutral-800, #626262));
812
923
  }
813
924
 
925
+ /**
926
+ * The icon renders inside the end container for floating and stacked labels and
927
+ * inside the native wrapper otherwise, the structure BREAKING.md documents for
928
+ * v9. Using `order` moves it past the slotted end content so the chevron stays
929
+ * on the field's trailing edge. The other themes leave it ahead of that
930
+ * content.
931
+ */
932
+ :host(.select-label-placement-stacked) .select-icon,
933
+ :host(.select-label-placement-floating) .select-icon {
934
+ order: 1;
935
+ }
936
+
814
937
  :host(.has-value) .select-icon {
815
938
  color: var(--token-text-subtle, var(--token-primitives-neutral-1000, #3b3b3b));
816
939
  }
@@ -849,16 +972,4 @@ button {
849
972
 
850
973
  :host(.select-shape-rectangular) {
851
974
  --border-radius: var(--token-border-radius-0, var(--token-scale-0, 0px));
852
- }
853
-
854
- :host(.select-size-small) .select-wrapper-inner {
855
- height: var(--token-scale-1000, 40px);
856
- }
857
-
858
- :host(.select-size-medium) .select-wrapper-inner {
859
- height: var(--token-scale-1200, 48px);
860
- }
861
-
862
- :host(.select-size-large) .select-wrapper-inner {
863
- height: var(--token-scale-1400, 56px);
864
975
  }
@@ -1,7 +1,6 @@
1
1
  /*!
2
2
  * (C) Ionic http://ionicframework.com - MIT License
3
3
  */
4
- import caretDownRegular from "@phosphor-icons/core/assets/regular/caret-down.svg";
5
4
  import { Build, Host, h, forceUpdate } from "@stencil/core";
6
5
  import { ENABLE_HTML_CONTENT_DEFAULT } from "../../utils/config";
7
6
  import { compareOptions, createNotchController, createStartContainerController, isOptionSelected, checkInvalidState, } from "../../utils/forms/index";
@@ -36,9 +35,8 @@ import { getIonTheme } from "../../global/ionic-global";
36
35
  * @part bottom - The container element for helper text, error text, and counter.
37
36
  * @part wrapper - The clickable label element that wraps the entire form field (label text, slots, selected values or placeholder, and toggle icons).
38
37
  * @part start - The wrapper element for the content in the start slot.
39
- * @part control - The wrapper element containing the native select control. In the `"ios"` and `"md"` themes it also contains the label, and the dropdown icon when the label is not floating or stacked.
40
- * @part end - The wrapper element for the content in the end slot. In the `"ios"` and `"md"` themes it also contains the dropdown icon when the label is floating or stacked.
41
- * @part inner - The wrapper element containing the start, control and end wrappers and the dropdown icon. Only rendered in the `"ionic"` theme.
38
+ * @part control - The wrapper element containing the label, the native select control, and the dropdown icon when the label is not floating or stacked. The `"ionic"` theme flattens this wrapper, so it cannot be given a box of its own there.
39
+ * @part end - The wrapper element for the content in the end slot. It also contains the dropdown icon when the label is floating or stacked.
42
40
  */
43
41
  export class Select {
44
42
  constructor() {
@@ -834,24 +832,13 @@ export class Select {
834
832
  renderStartContainer() {
835
833
  return (h("div", { key: "start", class: "select-start", part: "start", ref: (el) => (this.startContainerEl = el) }, h("slot", { name: "start" })));
836
834
  }
837
- renderNativeWrapper() {
838
- return (h("div", { class: "native-wrapper", ref: (el) => (this.nativeWrapperEl = el), part: "container" }, this.renderSelectText(), this.renderListbox()));
839
- }
840
- /**
841
- * The ionic theme keeps the label above a field box that wraps the slots and
842
- * the control, so the label can size independently of the slotted content.
843
- */
844
- renderIonicField() {
845
- return [
846
- this.renderLabel(),
847
- h("div", { key: "inner", class: "select-wrapper-inner", part: "inner" }, this.fill === 'outline' && h("div", { key: "outline", class: "select-outline" }), this.renderStartContainer(), h("div", { key: "control", class: "select-control", part: "control" }, this.renderNativeWrapper()), h("div", { key: "end", class: "select-end", part: "end" }, h("slot", { name: "end" })), this.renderSelectIcon()),
848
- ];
849
- }
850
835
  /**
851
- * The ios and md themes nest the label alongside the control so a floating
852
- * label can escape it and clear the start and end slots.
836
+ * Every theme renders the same label and control structure, aside from the md
837
+ * outline container below. The label is nested alongside the control so the
838
+ * ios and md floating label can escape it and clear the start and end slots.
839
+ * The ionic theme lifts it outside the field with grid instead.
853
840
  */
854
- renderNativeField() {
841
+ renderField() {
855
842
  const { fill, labelPlacement } = this;
856
843
  const hasOutlineFill = getIonTheme(this) === 'md' && fill === 'outline';
857
844
  const hasFloatingOrStackedLabel = labelPlacement === 'floating' || labelPlacement === 'stacked';
@@ -993,16 +980,9 @@ export class Select {
993
980
  else if (this.toggleIcon != null) {
994
981
  return this.toggleIcon;
995
982
  }
996
- // Determine the theme and map to default icons
983
+ // Determine the theme and map to the default icon
997
984
  const theme = getIonTheme(this);
998
- const defaultIcons = {
999
- ios: chevronExpand,
1000
- ionic: caretDownRegular,
1001
- md: caretDownSharp,
1002
- };
1003
- // Get the default icon based on the theme, falling back to 'md' icon if necessary
1004
- const defaultIcon = defaultIcons[theme] || defaultIcons.md;
1005
- // Return the configured select expanded icon or the default icon
985
+ const defaultIcon = theme === 'ios' ? chevronExpand : caretDownSharp;
1006
986
  return config.get('selectExpandedIcon', defaultIcon);
1007
987
  }
1008
988
  /**
@@ -1016,15 +996,9 @@ export class Select {
1016
996
  if (this.toggleIcon) {
1017
997
  return this.toggleIcon;
1018
998
  }
1019
- // Determine the theme and map to default icons
999
+ // Determine the theme and map to the default icon
1020
1000
  const theme = getIonTheme(this);
1021
- const defaultIcons = {
1022
- ios: chevronExpand,
1023
- ionic: caretDownRegular,
1024
- md: caretDownSharp,
1025
- };
1026
- // Get the default icon based on the theme, falling back to 'md' icon if necessary
1027
- const defaultIcon = defaultIcons[theme] || defaultIcons.md;
1001
+ const defaultIcon = theme === 'ios' ? chevronExpand : caretDownSharp;
1028
1002
  return config.get('selectCollapsedIcon', defaultIcon);
1029
1003
  }
1030
1004
  getHintTextId() {
@@ -1076,7 +1050,7 @@ export class Select {
1076
1050
  const hasValue = this.hasValue();
1077
1051
  renderHiddenInput(true, el, name, parseValue(value), disabled);
1078
1052
  const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || hasFocus || isExpanded));
1079
- return (h(Host, { key: '1169073985fabca41a2c0a15f07d155a19fd1197', onClick: this.onClick, class: createColorClasses(this.color, {
1053
+ return (h(Host, { key: 'd6d5a554df0aabf73531762d3e8f7f7757f1dd7e', onClick: this.onClick, class: createColorClasses(this.color, {
1080
1054
  [theme]: true,
1081
1055
  'in-item': inItem,
1082
1056
  'in-item-color': hostContext('ion-item.ion-color', el),
@@ -1085,6 +1059,7 @@ export class Select {
1085
1059
  'has-expanded-icon': expandedIcon !== undefined,
1086
1060
  'has-value': hasValue,
1087
1061
  'label-floating': labelShouldFloat,
1062
+ 'has-label': this.hasLabel,
1088
1063
  'has-placeholder': placeholder !== undefined,
1089
1064
  'has-focus': hasFocus,
1090
1065
  // TODO(FW-6451): Remove `ion-focusable` class in favor of `has-focus`.
@@ -1095,7 +1070,7 @@ export class Select {
1095
1070
  [`select-shape-${shape}`]: shape !== undefined,
1096
1071
  [`select-label-placement-${labelPlacement}`]: true,
1097
1072
  [`select-size-${size}`]: size !== undefined,
1098
- }) }, h("label", { key: 'b384d441d2dcaff191d978ce7ee1fb2a4dd74545', class: "select-wrapper", id: "select-label", onClick: this.onLabelClick, part: "wrapper" }, theme === 'ionic' ? this.renderIonicField() : this.renderNativeField(), shouldRenderHighlight && h("div", { key: '114d10e8e1aaa6fda0b9a6b35de52b37afe79b25', class: "select-highlight" })), this.renderBottomContent()));
1073
+ }) }, h("label", { key: '9ef1351faed0a57fc0911705102dd115ca72ed48', class: "select-wrapper", id: "select-label", onClick: this.onLabelClick, part: "wrapper" }, this.renderField(), shouldRenderHighlight && h("div", { key: '7f384deb139daec2556636fa07d6a384da04b437', class: "select-highlight" })), this.renderBottomContent()));
1099
1074
  }
1100
1075
  static get is() { return "ion-select"; }
1101
1076
  static get encapsulation() { return "shadow"; }
@@ -1,8 +1,8 @@
1
1
  /*!
2
2
  * (C) Ionic http://ionicframework.com - MIT License
3
3
  */
4
+ import { config } from "../../global/config";
4
5
  import { getIonMode, getIonTheme } from "../../global/ionic-global";
5
- import xRegular from "@phosphor-icons/core/assets/regular/x.svg";
6
6
  import { Host, forceUpdate, h } from "@stencil/core";
7
7
  import { getOverlayLabelJustify, getOverlayLabelPlacement } from "../../utils/overlay-control-label";
8
8
  import { safeCall } from "../../utils/overlays";
@@ -65,14 +65,16 @@ export class SelectModal {
65
65
  option.checked = ev.detail.checked;
66
66
  }
67
67
  }
68
- get cancelButtonIcon() {
68
+ /**
69
+ * Get the icon to use for the cancel icon.
70
+ * Use the icon set in the config.
71
+ * If no icon is set in the config, use the default icon.
72
+ */
73
+ get selectModalCancelIcon() {
74
+ // Determine the theme and map to the default icon
69
75
  const theme = getIonTheme(this);
70
- const icons = {
71
- ios: closeOutline,
72
- md: closeSharp,
73
- ionic: xRegular,
74
- };
75
- return icons[theme];
76
+ const defaultIcon = theme === 'ios' ? closeOutline : closeSharp;
77
+ return config.get('selectModalCancelIcon', defaultIcon);
76
78
  }
77
79
  getModalContextClasses() {
78
80
  const el = this.el;
@@ -166,10 +168,10 @@ export class SelectModal {
166
168
  });
167
169
  }
168
170
  render() {
169
- return (h(Host, { key: '42d29e9c9a0b34243014e2d573349720ef42d0f4', class: {
171
+ return (h(Host, { key: '4f80b69495a5fdcc4d99f72aa035264e1d283012', class: {
170
172
  [getIonMode(this)]: true,
171
173
  ...this.getModalContextClasses(),
172
- } }, h("ion-header", { key: '7fdccbdbb2df084cc6f46e0bc670420994876c23' }, h("ion-toolbar", { key: '43aec16af281bd7b8da6472793fd66f4d7e2c062' }, this.header !== undefined && h("ion-title", { key: '7abe8c10fe6bfd8ead09dfc12e1317055096e010' }, this.header), h("ion-buttons", { key: '3d5e1847487bdbf78165b97df063258ef96c93bd', slot: "end" }, h("ion-button", { key: '004fff6115dbeabcc6090fe35b5d4006fb96ec34', "aria-label": this.cancelIcon ? this.cancelText : undefined, "data-focus-order": "2", onClick: () => this.closeModal() }, this.cancelIcon ? (h("ion-icon", { "aria-hidden": "true", slot: "icon-only", icon: this.cancelButtonIcon })) : (this.cancelText))))), h("ion-content", { key: 'dede04ba473ff70e60320d1ed0313c15f7707e4f' }, h("ion-list", { key: '2064751ebacd1599ec097e43cd8b982ac8ce3b54' }, this.multiple === true ? this.renderCheckboxOptions() : this.renderRadioOptions()))));
174
+ } }, h("ion-header", { key: '59fd93f200eeed35e411bc12d1355747d6d3b003' }, h("ion-toolbar", { key: 'd443f633558101e8623c3d7aeab62b5a8dbaaea5' }, this.header !== undefined && h("ion-title", { key: '5038f4d67ec9ce335c9a543e209dc1e5e669f802' }, this.header), h("ion-buttons", { key: '047fd2497d20324433ca175441d60cf17095dadb', slot: "end" }, h("ion-button", { key: '0058eee326e1540c969decd9b8a9baa5b307dfde', "aria-label": this.cancelIcon ? this.cancelText : undefined, "data-focus-order": "2", onClick: () => this.closeModal() }, this.cancelIcon ? (h("ion-icon", { "aria-hidden": "true", slot: "icon-only", icon: this.selectModalCancelIcon })) : (this.cancelText))))), h("ion-content", { key: '1cde46ff794118bf086735289b83d6354ee4bc99' }, h("ion-list", { key: '19e238faabd981565590723323fa8442a77eb8b4' }, this.multiple === true ? this.renderCheckboxOptions() : this.renderRadioOptions()))));
173
175
  }
174
176
  static get is() { return "ion-select-modal"; }
175
177
  static get encapsulation() { return "scoped"; }