@ionic/core 8.8.19 → 8.8.20-dev.11787158518.168a2fea

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 (799) hide show
  1. package/components/index.js +1 -1
  2. package/components/ion-accordion-group.js +1 -1
  3. package/components/ion-accordion.js +1 -1
  4. package/components/ion-action-sheet.js +1 -1
  5. package/components/ion-alert.js +1 -1
  6. package/components/ion-app.js +1 -1
  7. package/components/ion-avatar.js +1 -1
  8. package/components/ion-back-button.js +1 -1
  9. package/components/ion-backdrop.js +1 -1
  10. package/components/ion-badge.js +1 -1
  11. package/components/ion-breadcrumb.js +1 -1
  12. package/components/ion-breadcrumbs.js +1 -1
  13. package/components/ion-button.js +1 -1
  14. package/components/ion-buttons.js +1 -1
  15. package/components/ion-card-content.js +1 -1
  16. package/components/ion-card-header.js +1 -1
  17. package/components/ion-card-subtitle.js +1 -1
  18. package/components/ion-card-title.js +1 -1
  19. package/components/ion-card.js +1 -1
  20. package/components/ion-checkbox.js +1 -1
  21. package/components/ion-chip.js +1 -1
  22. package/components/ion-col.js +1 -1
  23. package/components/ion-content.js +1 -1
  24. package/components/ion-datetime-button.js +1 -1
  25. package/components/ion-datetime.js +1 -1
  26. package/components/ion-fab-button.js +1 -1
  27. package/components/ion-fab-list.js +1 -1
  28. package/components/ion-fab.js +1 -1
  29. package/components/ion-footer.js +1 -1
  30. package/components/ion-grid.js +1 -1
  31. package/components/ion-header.js +1 -1
  32. package/components/ion-icon.js +1 -1
  33. package/components/ion-img.js +1 -1
  34. package/components/ion-infinite-scroll-content.js +1 -1
  35. package/components/ion-infinite-scroll.js +1 -1
  36. package/components/ion-input-otp.js +1 -1
  37. package/components/ion-input-password-toggle.js +1 -1
  38. package/components/ion-input.js +1 -1
  39. package/components/ion-item-divider.js +1 -1
  40. package/components/ion-item-group.js +1 -1
  41. package/components/ion-item-option.js +1 -1
  42. package/components/ion-item-options.js +1 -1
  43. package/components/ion-item-sliding.js +1 -1
  44. package/components/ion-item.js +1 -1
  45. package/components/ion-label.js +1 -1
  46. package/components/ion-list-header.js +1 -1
  47. package/components/ion-list.js +1 -1
  48. package/components/ion-loading.js +1 -1
  49. package/components/ion-menu-button.js +1 -1
  50. package/components/ion-menu-toggle.js +1 -1
  51. package/components/ion-menu.js +1 -1
  52. package/components/ion-modal.js +1 -1
  53. package/components/ion-nav-link.js +1 -1
  54. package/components/ion-nav.js +1 -1
  55. package/components/ion-note.js +1 -1
  56. package/components/ion-picker-column-option.js +1 -1
  57. package/components/ion-picker-column.js +1 -1
  58. package/components/ion-picker.js +1 -1
  59. package/components/ion-popover.js +1 -1
  60. package/components/ion-progress-bar.js +1 -1
  61. package/components/ion-radio-group.js +1 -1
  62. package/components/ion-radio.js +1 -1
  63. package/components/ion-range.js +1 -1
  64. package/components/ion-refresher-content.js +1 -1
  65. package/components/ion-refresher.js +1 -1
  66. package/components/ion-reorder-group.js +1 -1
  67. package/components/ion-reorder.js +1 -1
  68. package/components/ion-ripple-effect.js +1 -1
  69. package/components/ion-route-redirect.js +1 -1
  70. package/components/ion-route.js +1 -1
  71. package/components/ion-router-link.js +1 -1
  72. package/components/ion-router-outlet.js +1 -1
  73. package/components/ion-router.js +1 -1
  74. package/components/ion-row.js +1 -1
  75. package/components/ion-searchbar.js +1 -1
  76. package/components/ion-segment-button.js +1 -1
  77. package/components/ion-segment-content.js +1 -1
  78. package/components/ion-segment-view.js +1 -1
  79. package/components/ion-segment.js +1 -1
  80. package/components/ion-select-modal.js +1 -1
  81. package/components/ion-select-option.js +1 -1
  82. package/components/ion-select-popover.js +1 -1
  83. package/components/ion-select.js +1 -1
  84. package/components/ion-skeleton-text.js +1 -1
  85. package/components/ion-spinner.js +1 -1
  86. package/components/ion-split-pane.js +1 -1
  87. package/components/ion-tab-bar.js +1 -1
  88. package/components/ion-tab-button.js +1 -1
  89. package/components/ion-tab.js +1 -1
  90. package/components/ion-tabs.js +1 -1
  91. package/components/ion-text.js +1 -1
  92. package/components/ion-textarea.js +1 -1
  93. package/components/ion-thumbnail.js +1 -1
  94. package/components/ion-title.js +1 -1
  95. package/components/ion-toast.js +1 -1
  96. package/components/ion-toggle.js +1 -1
  97. package/components/ion-toolbar.js +1 -1
  98. package/components/p--m5cCjbK.js +4 -0
  99. package/components/p-1jI5oW-W.js +4 -0
  100. package/components/{p-6J0vc7Z8.js → p-63OhffQv.js} +1 -1
  101. package/components/p-8FN7p701.js +4 -0
  102. package/components/p-B4uHHhPK.js +4 -0
  103. package/components/p-BMPN55of.js +4 -0
  104. package/components/p-BNJOu1Q2.js +4 -0
  105. package/components/p-BOvLNVKq.js +4 -0
  106. package/components/p-BSQPZ79H.js +4 -0
  107. package/components/p-BeamQXHF.js +4 -0
  108. package/components/p-BhamHSw3.js +4 -0
  109. package/components/p-Bjig0DJK.js +4 -0
  110. package/components/p-BjluhQMI.js +4 -0
  111. package/components/p-BlsIikdZ.js +4 -0
  112. package/components/p-BqPNzJf6.js +4 -0
  113. package/components/p-BrD9Xv62.js +4 -0
  114. package/components/p-BvJqoZ5R.js +4 -0
  115. package/components/p-Bz6z3Asd.js +4 -0
  116. package/components/p-C5KYjZWD.js +4 -0
  117. package/components/p-C6HnVvHO.js +4 -0
  118. package/components/p-C7jvh5Wy.js +4 -0
  119. package/components/p-C9BGR5fy.js +4 -0
  120. package/components/p-CB-y1CdP.js +4 -0
  121. package/components/p-CEW4RXZO.js +4 -0
  122. package/components/p-CHH3loEE.js +4 -0
  123. package/components/p-CJKUWjmg.js +4 -0
  124. package/components/{p-qMmFisyx.js → p-CMLAwl_N.js} +1 -1
  125. package/components/{p-C7II1iDj.js → p-C_phlPMC.js} +1 -1
  126. package/components/p-CbhUdtjf.js +4 -0
  127. package/components/p-CejmQs3h.js +4 -0
  128. package/components/p-CtZqa4HM.js +4 -0
  129. package/components/p-D7-vHX0A.js +4 -0
  130. package/components/p-D9qIVSWm.js +4 -0
  131. package/components/p-DD5fQ4EQ.js +4 -0
  132. package/components/p-DE-3iMNW.js +4 -0
  133. package/components/p-DFvZn99E.js +4 -0
  134. package/components/p-DHFt2rdc.js +4 -0
  135. package/components/p-DM-PrAoh.js +4 -0
  136. package/components/p-DSzSbVP2.js +4 -0
  137. package/components/{p--JUspHvy.js → p-DV85C0e0.js} +1 -1
  138. package/components/p-DWCzVL3Y.js +4 -0
  139. package/components/p-D_RCyzwu.js +4 -0
  140. package/components/p-D_tD8r3L.js +4 -0
  141. package/components/p-DaA_8eqt.js +4 -0
  142. package/components/p-DjCtLZbF.js +4 -0
  143. package/components/p-Dmd2xqCe.js +4 -0
  144. package/components/p-Dojwmvde.js +4 -0
  145. package/components/{p-BkKAANMJ.js → p-DwpKZ6rl.js} +1 -1
  146. package/components/p-DzRT60Tw.js +4 -0
  147. package/components/p-G0TxqHfe.js +4 -0
  148. package/components/p-G6JR-cr_.js +4 -0
  149. package/components/p-GG5GhznE.js +4 -0
  150. package/components/p-TXPDHL13.js +4 -0
  151. package/components/p-UIBJkZf8.js +4 -0
  152. package/components/p-_IKFD3ID.js +4 -0
  153. package/components/p-byZM6qHV.js +4 -0
  154. package/components/p-dKq2jIum.js +4 -0
  155. package/components/p-fruGqVHh.js +4 -0
  156. package/components/p-iYhH60Tc.js +4 -0
  157. package/components/p-ia3IDdJS.js +4 -0
  158. package/components/{p-DqLB8yFQ.js → p-ryyf_ItD.js} +1 -1
  159. package/dist/cjs/{animation-Ch16T-Nb.js → animation-C0mOHzej.js} +4 -4
  160. package/dist/cjs/{app-globals-Dd89e0MR.js → app-globals-BREG4twP.js} +1 -1
  161. package/dist/cjs/{button-active-AWp_ygDP.js → button-active-CVMevT9a.js} +3 -3
  162. package/dist/cjs/config-CjUbvdPW.js +36 -0
  163. package/dist/cjs/{dir-DD0jPVH3.js → dir-zwDPRE5K.js} +2 -3
  164. package/dist/cjs/{format-BUFWn4Bn.js → format-pp0Du3K-.js} +40 -30
  165. package/dist/cjs/{framework-delegate-CEzl4MEA.js → framework-delegate-Dfo5XsGv.js} +5 -7
  166. package/dist/cjs/{gesture-controller-dtqlP_q4.js → gesture-controller-BDUH7687.js} +15 -8
  167. package/dist/cjs/{haptic-ClPPQ_PS.js → haptic-Ch-X4gRx.js} +2 -3
  168. package/dist/cjs/{hardware-back-button-CXmUnTJC.js → hardware-back-button-fqpYh-kd.js} +4 -4
  169. package/dist/cjs/{helpers-DdZyl6WL.js → helpers-YPQybDph.js} +4 -4
  170. package/dist/cjs/index-B7zJsYWS.js +429 -0
  171. package/dist/cjs/{index-CukZnH1U.js → index-BLdJCcJY.js} +5 -5
  172. package/dist/cjs/{index-MWAIyVLl.js → index-DDg31ZF5.js} +3 -3
  173. package/dist/cjs/{index-DOiZqxWZ.js → index-DXsPSne6.js} +6 -7
  174. package/dist/cjs/{index-BJ2-LydH.js → index-DwlRtFZe.js} +9 -3
  175. package/dist/cjs/{index-BfaXsATC.js → index-uvry__L4.js} +31 -14
  176. package/dist/cjs/{index-DqmRDbxg.js → index-wOmugbdg.js} +1 -1
  177. package/dist/cjs/{index-CD92bI7B.js → index-zVCah4Uz.js} +2 -2
  178. package/dist/cjs/index.cjs.js +19 -19
  179. package/dist/cjs/{input-shims-CPKgrIe3.js → input-shims-Cbu1fcye.js} +10 -12
  180. package/dist/cjs/input.utils-BZdMWVrt.js +35 -0
  181. package/dist/cjs/ion-accordion_2.cjs.entry.js +369 -341
  182. package/dist/cjs/ion-action-sheet.cjs.entry.js +188 -77
  183. package/dist/cjs/ion-alert.cjs.entry.js +274 -112
  184. package/dist/cjs/ion-app_8.cjs.entry.js +307 -190
  185. package/dist/cjs/ion-avatar_3.cjs.entry.js +10 -4
  186. package/dist/cjs/ion-back-button.cjs.entry.js +48 -24
  187. package/dist/cjs/ion-backdrop.cjs.entry.js +18 -14
  188. package/dist/cjs/ion-breadcrumb_2.cjs.entry.js +200 -122
  189. package/dist/cjs/ion-button_2.cjs.entry.js +139 -67
  190. package/dist/cjs/ion-card_5.cjs.entry.js +83 -31
  191. package/dist/cjs/ion-checkbox.cjs.entry.js +153 -102
  192. package/dist/cjs/ion-chip.cjs.entry.js +17 -11
  193. package/dist/cjs/ion-col_3.cjs.entry.js +134 -10
  194. package/dist/cjs/ion-datetime-button.cjs.entry.js +254 -242
  195. package/dist/cjs/ion-datetime.cjs.entry.js +2770 -0
  196. package/dist/cjs/ion-fab_3.cjs.entry.js +140 -82
  197. package/dist/cjs/ion-img.cjs.entry.js +35 -13
  198. package/dist/cjs/ion-infinite-scroll_2.cjs.entry.js +101 -73
  199. package/dist/cjs/ion-input-otp.cjs.entry.js +435 -372
  200. package/dist/cjs/ion-input-password-toggle.cjs.entry.js +36 -22
  201. package/dist/cjs/ion-input.cjs.entry.js +343 -212
  202. package/dist/cjs/ion-item-option_3.cjs.entry.js +95 -55
  203. package/dist/cjs/ion-item_8.cjs.entry.js +192 -93
  204. package/dist/cjs/ion-loading.cjs.entry.js +147 -61
  205. package/dist/cjs/ion-menu_3.cjs.entry.js +169 -107
  206. package/dist/cjs/ion-modal.cjs.entry.js +456 -262
  207. package/dist/cjs/ion-nav_2.cjs.entry.js +102 -159
  208. package/dist/cjs/ion-picker-column-option.cjs.entry.js +38 -34
  209. package/dist/cjs/ion-picker-column.cjs.entry.js +418 -406
  210. package/dist/cjs/ion-picker.cjs.entry.js +402 -393
  211. package/dist/cjs/ion-popover.cjs.entry.js +320 -206
  212. package/dist/cjs/ion-progress-bar.cjs.entry.js +32 -26
  213. package/dist/cjs/ion-radio_2.cjs.entry.js +208 -135
  214. package/dist/cjs/ion-range.cjs.entry.js +304 -239
  215. package/dist/cjs/ion-refresher_2.cjs.entry.js +166 -94
  216. package/dist/cjs/ion-reorder_2.cjs.entry.js +54 -24
  217. package/dist/cjs/ion-ripple-effect.cjs.entry.js +14 -14
  218. package/dist/cjs/ion-route_4.cjs.entry.js +176 -72
  219. package/dist/cjs/ion-searchbar.cjs.entry.js +291 -200
  220. package/dist/cjs/ion-segment-content.cjs.entry.js +2 -2
  221. package/dist/cjs/ion-segment-view.cjs.entry.js +28 -17
  222. package/dist/cjs/ion-segment_2.cjs.entry.js +169 -126
  223. package/dist/cjs/ion-select-modal.cjs.entry.js +105 -49
  224. package/dist/cjs/ion-select_3.cjs.entry.js +787 -260
  225. package/dist/cjs/ion-spinner.cjs.entry.js +24 -10
  226. package/dist/cjs/ion-split-pane.cjs.entry.js +29 -16
  227. package/dist/cjs/ion-tab-bar_2.cjs.entry.js +101 -42
  228. package/dist/cjs/ion-tab_2.cjs.entry.js +54 -28
  229. package/dist/cjs/ion-text.cjs.entry.js +11 -5
  230. package/dist/cjs/ion-textarea.cjs.entry.js +296 -189
  231. package/dist/cjs/ion-toast.cjs.entry.js +237 -118
  232. package/dist/cjs/ion-toggle.cjs.entry.js +175 -122
  233. package/dist/cjs/{ionic-global-BerQGEpE.js → ionic-global-k6hOWWpn.js} +13 -8
  234. package/dist/cjs/ionic.cjs.js +4 -4
  235. package/dist/cjs/{ios.transition-CTiTDh3m.js → ios.transition-zTmJz8T-.js} +14 -18
  236. package/dist/cjs/{item-multiple-inputs-jOJZE_I0.js → item-multiple-inputs-BdYSbfKN.js} +1 -1
  237. package/dist/cjs/{keyboard-hHzlEQpk.js → keyboard-Cix5TVkD.js} +2 -2
  238. package/dist/cjs/{keyboard-UuAS4D_9.js → keyboard-cHxZlTyz.js} +2 -2
  239. package/dist/cjs/{keyboard-controller-GXBiBRKS.js → keyboard-controller-PtZoN2GS.js} +6 -6
  240. package/dist/cjs/loader.cjs.js +4 -4
  241. package/dist/cjs/{md.transition-BpiTAaqF.js → md.transition-nb_4pUXu.js} +8 -9
  242. package/dist/cjs/overlay-control-label-D2sdL2O8.js +50 -0
  243. package/dist/cjs/{overlays-CQ_c1fko.js → overlays-KaNVDNqC.js} +48 -33
  244. package/dist/cjs/select-option-render-pULCGldr.js +123 -0
  245. package/dist/cjs/slot-mutation-controller-DPHmqXdV.js +397 -0
  246. package/dist/cjs/{status-tap-7FzRlXNr.js → status-tap-o9IIymsP.js} +4 -4
  247. package/dist/cjs/{swipe-back-DwTZiAc9.js → swipe-back-B7X9VOlH.js} +5 -5
  248. package/dist/cjs/{theme-CeDs6Hcv.js → theme-Bw0rpaNN.js} +6 -1
  249. package/dist/collection/collection-manifest.json +6 -10
  250. package/dist/collection/components/accordion/accordion.js +315 -312
  251. package/dist/collection/components/accordion-group/accordion-group.js +48 -25
  252. package/dist/collection/components/action-sheet/action-sheet.ios.css +228 -2
  253. package/dist/collection/components/action-sheet/action-sheet.js +173 -64
  254. package/dist/collection/components/action-sheet/action-sheet.md.css +174 -2
  255. package/dist/collection/components/action-sheet/test/basic/fixture.js +3 -0
  256. package/dist/collection/components/alert/alert.ios.css +279 -10
  257. package/dist/collection/components/alert/alert.js +257 -97
  258. package/dist/collection/components/alert/alert.md.css +268 -20
  259. package/dist/collection/components/app/app.js +3 -0
  260. package/dist/collection/components/back-button/back-button.js +42 -19
  261. package/dist/collection/components/backdrop/backdrop.js +16 -14
  262. package/dist/collection/components/badge/badge.js +6 -0
  263. package/dist/collection/components/breadcrumb/breadcrumb.js +91 -30
  264. package/dist/collection/components/breadcrumbs/breadcrumbs.js +103 -88
  265. package/dist/collection/components/button/button.js +132 -61
  266. package/dist/collection/components/buttons/buttons.js +13 -15
  267. package/dist/collection/components/card/card.js +54 -21
  268. package/dist/collection/components/card-header/card-header.js +12 -8
  269. package/dist/collection/components/card-subtitle/card-subtitle.js +6 -0
  270. package/dist/collection/components/card-title/card-title.js +6 -0
  271. package/dist/collection/components/checkbox/checkbox.js +147 -97
  272. package/dist/collection/components/chip/chip.js +14 -10
  273. package/dist/collection/components/col/col.js +127 -3
  274. package/dist/collection/components/content/content.js +93 -64
  275. package/dist/collection/components/datetime/datetime.ios.css +42 -2
  276. package/dist/collection/components/datetime/datetime.js +1042 -807
  277. package/dist/collection/components/datetime/datetime.md.css +42 -1
  278. package/dist/collection/components/datetime/utils/data.js +13 -14
  279. package/dist/collection/components/datetime/utils/format.js +21 -11
  280. package/dist/collection/components/datetime/utils/manipulation.js +8 -8
  281. package/dist/collection/components/datetime/utils/parse.js +10 -10
  282. package/dist/collection/components/datetime/utils/state.js +8 -2
  283. package/dist/collection/components/datetime/utils/validate.js +4 -5
  284. package/dist/collection/components/datetime-button/datetime-button.ios.css +5 -0
  285. package/dist/collection/components/datetime-button/datetime-button.js +247 -237
  286. package/dist/collection/components/datetime-button/datetime-button.md.css +5 -0
  287. package/dist/collection/components/fab/fab.js +20 -13
  288. package/dist/collection/components/fab-button/fab-button.js +104 -55
  289. package/dist/collection/components/fab-list/fab-list.js +10 -11
  290. package/dist/collection/components/footer/footer.js +50 -44
  291. package/dist/collection/components/grid/grid.js +4 -6
  292. package/dist/collection/components/header/header.js +35 -25
  293. package/dist/collection/components/img/img.js +34 -10
  294. package/dist/collection/components/infinite-scroll/infinite-scroll.js +73 -66
  295. package/dist/collection/components/infinite-scroll-content/infinite-scroll-content.js +20 -3
  296. package/dist/collection/components/input/input.ios.css +57 -26
  297. package/dist/collection/components/input/input.js +336 -206
  298. package/dist/collection/components/input/input.md.css +79 -43
  299. package/dist/collection/components/input-otp/input-otp.js +430 -368
  300. package/dist/collection/components/input-password-toggle/input-password-toggle.js +32 -19
  301. package/dist/collection/components/item/item.js +99 -53
  302. package/dist/collection/components/item-divider/item-divider.js +17 -12
  303. package/dist/collection/components/item-group/item-group.js +1 -1
  304. package/dist/collection/components/item-option/item-option.js +50 -22
  305. package/dist/collection/components/item-options/item-options.js +11 -8
  306. package/dist/collection/components/item-sliding/item-sliding.js +27 -21
  307. package/dist/collection/components/label/label.js +26 -6
  308. package/dist/collection/components/list/list.js +11 -8
  309. package/dist/collection/components/list-header/list-header.js +12 -2
  310. package/dist/collection/components/loading/loading.js +135 -51
  311. package/dist/collection/components/menu/menu.js +103 -61
  312. package/dist/collection/components/menu-button/menu-button.js +30 -21
  313. package/dist/collection/components/menu-toggle/menu-toggle.js +22 -15
  314. package/dist/collection/components/modal/animations/ios.enter.js +1 -1
  315. package/dist/collection/components/modal/animations/md.enter.js +1 -1
  316. package/dist/collection/components/modal/gestures/sheet.js +22 -10
  317. package/dist/collection/components/modal/gestures/swipe-to-close.js +15 -3
  318. package/dist/collection/components/modal/modal.js +398 -228
  319. package/dist/collection/components/modal/safe-area-utils.js +6 -7
  320. package/dist/collection/components/modal/test/fixtures.js +3 -0
  321. package/dist/collection/components/nav/nav.js +69 -247
  322. package/dist/collection/components/nav/view-controller.js +7 -1
  323. package/dist/collection/components/nav-link/nav-link.js +21 -10
  324. package/dist/collection/components/note/note.js +8 -2
  325. package/dist/collection/components/picker/picker.js +398 -390
  326. package/dist/collection/components/picker-column/picker-column.css +3 -0
  327. package/dist/collection/components/picker-column/picker-column.js +414 -404
  328. package/dist/collection/components/picker-column-option/picker-column-option.js +33 -31
  329. package/dist/collection/components/picker-column-option/picker-column-option.md.css +6 -1
  330. package/dist/collection/components/popover/animations/ios.enter.js +1 -2
  331. package/dist/collection/components/popover/animations/md.enter.js +1 -2
  332. package/dist/collection/components/popover/popover.ios.css +15 -0
  333. package/dist/collection/components/popover/popover.js +302 -185
  334. package/dist/collection/components/popover/popover.md.css +15 -0
  335. package/dist/collection/components/popover/test/fixture.js +1 -0
  336. package/dist/collection/components/popover/utils.js +4 -6
  337. package/dist/collection/components/progress-bar/progress-bar.js +27 -23
  338. package/dist/collection/components/radio/radio.js +102 -66
  339. package/dist/collection/components/radio-group/radio-group.js +101 -66
  340. package/dist/collection/components/radio-group/test/fixtures.js +2 -0
  341. package/dist/collection/components/range/range.js +298 -234
  342. package/dist/collection/components/refresher/refresher.js +110 -78
  343. package/dist/collection/components/refresher-content/refresher-content.js +41 -4
  344. package/dist/collection/components/reorder/reorder.js +2 -1
  345. package/dist/collection/components/reorder-group/reorder-group.js +44 -15
  346. package/dist/collection/components/ripple-effect/ripple-effect.js +12 -13
  347. package/dist/collection/components/route/route.js +39 -10
  348. package/dist/collection/components/route-redirect/route-redirect.js +31 -0
  349. package/dist/collection/components/router/router.js +37 -33
  350. package/dist/collection/components/router/utils/dom.js +25 -7
  351. package/dist/collection/components/router/utils/matching.js +7 -9
  352. package/dist/collection/components/router/utils/parser.js +1 -1
  353. package/dist/collection/components/router/utils/path.js +0 -1
  354. package/dist/collection/components/router-link/router-link.js +37 -12
  355. package/dist/collection/components/router-outlet/router-outlet.js +82 -21
  356. package/dist/collection/components/row/row.js +1 -1
  357. package/dist/collection/components/searchbar/searchbar.js +289 -199
  358. package/dist/collection/components/segment/segment.js +120 -85
  359. package/dist/collection/components/segment-button/segment-button.js +43 -37
  360. package/dist/collection/components/segment-content/segment-content.js +1 -1
  361. package/dist/collection/components/segment-view/segment-view.js +26 -16
  362. package/dist/collection/components/select/select.ios.css +96 -69
  363. package/dist/collection/components/select/select.js +629 -213
  364. package/dist/collection/components/select/select.md.css +118 -85
  365. package/dist/collection/components/select-modal/select-modal.ios.css +218 -0
  366. package/dist/collection/components/select-modal/select-modal.js +92 -38
  367. package/dist/collection/components/select-modal/select-modal.md.css +164 -0
  368. package/dist/collection/components/select-modal/test/fixtures.js +8 -1
  369. package/dist/collection/components/select-option/select-option.js +110 -9
  370. package/dist/collection/components/select-popover/select-popover.ios.css +218 -0
  371. package/dist/collection/components/select-popover/select-popover.js +103 -36
  372. package/dist/collection/components/select-popover/select-popover.md.css +164 -0
  373. package/dist/collection/components/select-popover/test/fixtures.js +8 -1
  374. package/dist/collection/components/skeleton-text/skeleton-text.js +12 -8
  375. package/dist/collection/components/spinner/spinner.js +21 -9
  376. package/dist/collection/components/split-pane/split-pane.js +27 -15
  377. package/dist/collection/components/tab/tab.js +17 -6
  378. package/dist/collection/components/tab-bar/tab-bar.js +32 -14
  379. package/dist/collection/components/tab-button/tab-button.js +62 -23
  380. package/dist/collection/components/tabs/tabs.js +33 -20
  381. package/dist/collection/components/text/text.js +8 -2
  382. package/dist/collection/components/textarea/textarea.ios.css +94 -62
  383. package/dist/collection/components/textarea/textarea.js +287 -181
  384. package/dist/collection/components/textarea/textarea.md.css +103 -77
  385. package/dist/collection/components/thumbnail/thumbnail.js +1 -1
  386. package/dist/collection/components/title/title.js +18 -2
  387. package/dist/collection/components/toast/toast.js +223 -106
  388. package/dist/collection/components/toggle/toggle.js +167 -115
  389. package/dist/collection/components/toolbar/toolbar.js +15 -7
  390. package/dist/collection/global/config.js +4 -6
  391. package/dist/collection/global/ionic-global.js +8 -2
  392. package/dist/collection/index.js +1 -1
  393. package/dist/collection/utils/animation/animation.js +3 -3
  394. package/dist/collection/utils/config.js +5 -4
  395. package/dist/collection/utils/focus-controller/index.js +1 -1
  396. package/dist/collection/utils/focus-trap.js +3 -3
  397. package/dist/collection/utils/forms/index.js +1 -0
  398. package/dist/collection/utils/forms/start-container-controller.js +132 -0
  399. package/dist/collection/utils/framework-delegate.js +4 -6
  400. package/dist/collection/utils/gesture/gesture-controller.js +15 -8
  401. package/dist/collection/utils/gesture/index.js +10 -2
  402. package/dist/collection/utils/hardware-back-button.js +3 -3
  403. package/dist/collection/utils/helpers.js +2 -2
  404. package/dist/collection/utils/input-shims/hacks/scroll-assist.js +4 -5
  405. package/dist/collection/utils/input-shims/hacks/scroll-data.js +1 -2
  406. package/dist/collection/utils/keyboard/keyboard-controller.js +5 -5
  407. package/dist/collection/utils/keyboard/keyboard.js +1 -1
  408. package/dist/collection/utils/logging/index.js +23 -4
  409. package/dist/collection/utils/menu-controller/index.js +1 -2
  410. package/dist/collection/utils/native/haptic.js +2 -3
  411. package/dist/collection/utils/native/keyboard.js +2 -2
  412. package/dist/collection/utils/native/status-bar.js +1 -1
  413. package/dist/collection/utils/overlay-control-label.js +45 -0
  414. package/dist/collection/utils/overlays.js +38 -23
  415. package/dist/collection/utils/platform.js +4 -5
  416. package/dist/collection/utils/rtl/dir.js +2 -3
  417. package/dist/collection/utils/sanitization/index.js +276 -20
  418. package/dist/collection/utils/select-option-render.js +118 -0
  419. package/dist/collection/utils/slot-mutation-controller.js +1 -2
  420. package/dist/collection/utils/test/playwright/apply-keyboard-focus.js +1 -1
  421. package/dist/collection/utils/test/playwright/drag-element.js +2 -3
  422. package/dist/collection/utils/test/playwright/generator.js +3 -4
  423. package/dist/collection/utils/test/playwright/page/event-spy.js +11 -12
  424. package/dist/collection/utils/test/playwright/page/utils/goto.js +4 -5
  425. package/dist/collection/utils/test/playwright/page/utils/set-content.js +1 -1
  426. package/dist/collection/utils/test/playwright/page/utils/set-ion-viewport.js +2 -3
  427. package/dist/collection/utils/test/press-keys.js +10 -17
  428. package/dist/collection/utils/theme.js +6 -1
  429. package/dist/collection/utils/transition/ios.transition.js +9 -13
  430. package/dist/collection/utils/transition/md.transition.js +3 -4
  431. package/dist/docs.json +557 -1257
  432. package/dist/esm/{animation-DLJpuoEz.js → animation-CGFdmGk9.js} +4 -4
  433. package/dist/esm/{app-globals-D0C5S4hU.js → app-globals-CYmMeGdU.js} +1 -1
  434. package/dist/esm/{button-active-CXXy0FIE.js → button-active-BDOsVAiZ.js} +3 -3
  435. package/dist/esm/config-DWCzVL3Y.js +32 -0
  436. package/dist/esm/{dir-o8OKV5aD.js → dir-Dojwmvde.js} +2 -3
  437. package/dist/esm/{format-CAmvpAez.js → format-Dcwga61t.js} +41 -31
  438. package/dist/esm/{framework-delegate-B9yvYzqV.js → framework-delegate-BHTU2Ip9.js} +5 -7
  439. package/dist/esm/{gesture-controller-BTEOs1at.js → gesture-controller-TXPDHL13.js} +15 -8
  440. package/dist/esm/{haptic-DzAMWJuk.js → haptic-Cq4UAeka.js} +2 -3
  441. package/dist/esm/{hardware-back-button-B93Gru0Y.js → hardware-back-button-gLJHMX_F.js} +4 -4
  442. package/dist/esm/{helpers-DkCLSLI9.js → helpers-CAGf8Wgp.js} +4 -4
  443. package/dist/esm/{index-DV3sJJW8.js → index-BvabGprD.js} +2 -2
  444. package/dist/esm/index-CKM1DdGm.js +424 -0
  445. package/dist/esm/{index-tcQvqkiX.js → index-ChhhtsGZ.js} +32 -15
  446. package/dist/esm/{index-DwNKJodj.js → index-Clc-28O1.js} +3 -3
  447. package/dist/esm/{index-DdeElWma.js → index-CqneaaGd.js} +6 -7
  448. package/dist/esm/{index-Bck1OwMs.js → index-DcPaH5uL.js} +9 -3
  449. package/dist/esm/{index-B_8X7INq.js → index-T0JxBI8V.js} +2 -2
  450. package/dist/esm/{index-Dsz7OTeL.js → index-WlteAIqz.js} +5 -5
  451. package/dist/esm/index.js +17 -16
  452. package/dist/esm/{input-shims-d-hDv86G.js → input-shims-B8sfni1e.js} +10 -12
  453. package/dist/esm/input.utils-B1ValN_N.js +33 -0
  454. package/dist/esm/ion-accordion_2.entry.js +369 -341
  455. package/dist/esm/ion-action-sheet.entry.js +188 -77
  456. package/dist/esm/ion-alert.entry.js +273 -111
  457. package/dist/esm/ion-app_8.entry.js +307 -190
  458. package/dist/esm/ion-avatar_3.entry.js +10 -4
  459. package/dist/esm/ion-back-button.entry.js +48 -24
  460. package/dist/esm/ion-backdrop.entry.js +18 -14
  461. package/dist/esm/ion-breadcrumb_2.entry.js +200 -122
  462. package/dist/esm/ion-button_2.entry.js +139 -67
  463. package/dist/esm/ion-card_5.entry.js +83 -31
  464. package/dist/esm/ion-checkbox.entry.js +153 -102
  465. package/dist/esm/ion-chip.entry.js +17 -11
  466. package/dist/esm/ion-col_3.entry.js +134 -10
  467. package/dist/esm/ion-datetime-button.entry.js +254 -242
  468. package/dist/esm/ion-datetime.entry.js +2768 -0
  469. package/dist/esm/ion-fab_3.entry.js +140 -82
  470. package/dist/esm/ion-img.entry.js +35 -13
  471. package/dist/esm/ion-infinite-scroll_2.entry.js +100 -72
  472. package/dist/esm/ion-input-otp.entry.js +435 -372
  473. package/dist/esm/ion-input-password-toggle.entry.js +36 -22
  474. package/dist/esm/ion-input.entry.js +341 -210
  475. package/dist/esm/ion-item-option_3.entry.js +95 -55
  476. package/dist/esm/ion-item_8.entry.js +192 -93
  477. package/dist/esm/ion-loading.entry.js +146 -60
  478. package/dist/esm/ion-menu_3.entry.js +169 -107
  479. package/dist/esm/ion-modal.entry.js +456 -262
  480. package/dist/esm/ion-nav_2.entry.js +102 -159
  481. package/dist/esm/ion-picker-column-option.entry.js +38 -34
  482. package/dist/esm/ion-picker-column.entry.js +418 -406
  483. package/dist/esm/ion-picker.entry.js +402 -393
  484. package/dist/esm/ion-popover.entry.js +320 -206
  485. package/dist/esm/ion-progress-bar.entry.js +32 -26
  486. package/dist/esm/ion-radio_2.entry.js +208 -135
  487. package/dist/esm/ion-range.entry.js +304 -239
  488. package/dist/esm/ion-refresher_2.entry.js +164 -92
  489. package/dist/esm/ion-reorder_2.entry.js +54 -24
  490. package/dist/esm/ion-ripple-effect.entry.js +14 -14
  491. package/dist/esm/ion-route_4.entry.js +176 -72
  492. package/dist/esm/ion-searchbar.entry.js +291 -200
  493. package/dist/esm/ion-segment-content.entry.js +2 -2
  494. package/dist/esm/ion-segment-view.entry.js +28 -17
  495. package/dist/esm/ion-segment_2.entry.js +169 -126
  496. package/dist/esm/ion-select-modal.entry.js +105 -49
  497. package/dist/esm/ion-select_3.entry.js +787 -260
  498. package/dist/esm/ion-spinner.entry.js +24 -10
  499. package/dist/esm/ion-split-pane.entry.js +29 -16
  500. package/dist/esm/ion-tab-bar_2.entry.js +101 -42
  501. package/dist/esm/ion-tab_2.entry.js +54 -28
  502. package/dist/esm/ion-text.entry.js +11 -5
  503. package/dist/esm/ion-textarea.entry.js +295 -188
  504. package/dist/esm/ion-toast.entry.js +236 -117
  505. package/dist/esm/ion-toggle.entry.js +175 -122
  506. package/dist/esm/{ionic-global-Cp_eT4sZ.js → ionic-global-BVB7BrLT.js} +13 -8
  507. package/dist/esm/ionic.js +5 -5
  508. package/dist/esm/{ios.transition-CxNhMt4a.js → ios.transition-DXRCmcbC.js} +14 -18
  509. package/dist/esm/{item-multiple-inputs-DlNuqNJm.js → item-multiple-inputs-rU8VaNNg.js} +1 -1
  510. package/dist/esm/{keyboard-ywgs5efA.js → keyboard-Cj8mLJeq.js} +2 -2
  511. package/dist/esm/{keyboard-CUw4ekVy.js → keyboard-DAF8GNJ9.js} +2 -2
  512. package/dist/esm/{keyboard-controller-BaaVITYt.js → keyboard-controller-DEwoa1ev.js} +6 -6
  513. package/dist/esm/loader.js +5 -5
  514. package/dist/esm/{md.transition-IE4mC3kp.js → md.transition-BMngO4i_.js} +8 -9
  515. package/dist/esm/overlay-control-label-BSQPZ79H.js +47 -0
  516. package/dist/esm/{overlays-COCl_nm9.js → overlays-CPmIs9Ls.js} +48 -33
  517. package/dist/esm/select-option-render-C4m76VGH.js +121 -0
  518. package/dist/esm/slot-mutation-controller-DiE_C9un.js +393 -0
  519. package/dist/esm/{status-tap-HhO5eQI9.js → status-tap-CHB7KwIb.js} +4 -4
  520. package/dist/esm/{swipe-back-DK6afpuO.js → swipe-back-C9HW1bug.js} +5 -5
  521. package/dist/esm/{theme-DiVJyqlX.js → theme-byZM6qHV.js} +6 -1
  522. package/dist/html.html-data.json +52 -80
  523. package/dist/ionic/index.esm.js +1 -1
  524. package/dist/ionic/ionic.esm.js +1 -1
  525. package/dist/ionic/p-06ec7136.entry.js +4 -0
  526. package/dist/ionic/p-09fe4fa3.entry.js +4 -0
  527. package/dist/ionic/p-10d45a07.entry.js +4 -0
  528. package/dist/ionic/p-208c8a07.entry.js +4 -0
  529. package/dist/ionic/p-212474fa.entry.js +4 -0
  530. package/dist/ionic/p-2eef1396.entry.js +4 -0
  531. package/dist/ionic/p-347e005d.entry.js +4 -0
  532. package/dist/ionic/p-3a0b3f1d.entry.js +4 -0
  533. package/dist/ionic/p-3b071259.entry.js +4 -0
  534. package/dist/ionic/{p-c6e49f3f.entry.js → p-40424a88.entry.js} +1 -1
  535. package/dist/ionic/p-4204184c.entry.js +4 -0
  536. package/dist/ionic/p-47464391.entry.js +4 -0
  537. package/dist/ionic/p-4eOQC00Z.js +4 -0
  538. package/dist/ionic/p-4f9c9126.entry.js +4 -0
  539. package/dist/ionic/p-5JsKPLJD.js +4 -0
  540. package/dist/ionic/p-5bc485c6.entry.js +4 -0
  541. package/dist/ionic/p-603a61e6.entry.js +4 -0
  542. package/dist/ionic/p-60576951.entry.js +4 -0
  543. package/dist/ionic/p-67a81d33.entry.js +4 -0
  544. package/dist/ionic/p-6affb775.entry.js +4 -0
  545. package/dist/ionic/p-6f120c25.entry.js +4 -0
  546. package/dist/ionic/p-71c82b60.entry.js +4 -0
  547. package/dist/ionic/p-79325ffe.entry.js +4 -0
  548. package/dist/ionic/{p-DZaO33Mw.js → p-7CBuOvEo.js} +1 -1
  549. package/dist/ionic/p-7e4d51fa.entry.js +4 -0
  550. package/dist/ionic/p-7f5d4664.entry.js +4 -0
  551. package/dist/ionic/p-80ee82fc.entry.js +4 -0
  552. package/dist/ionic/p-84af7dbc.entry.js +4 -0
  553. package/dist/ionic/p-89ca830a.entry.js +4 -0
  554. package/dist/ionic/p-93b8ec8f.entry.js +4 -0
  555. package/dist/ionic/p-946f65c2.entry.js +4 -0
  556. package/dist/ionic/p-9c4b39fb.entry.js +4 -0
  557. package/dist/ionic/p-B1NEZUzQ.js +4 -0
  558. package/dist/ionic/p-B1ck5iy-.js +4 -0
  559. package/dist/ionic/{p-Cd4H8ft-.js → p-B4FrqdW0.js} +1 -1
  560. package/dist/ionic/p-BB0LlG4y.js +4 -0
  561. package/dist/ionic/p-BMPN55of.js +4 -0
  562. package/dist/ionic/p-BSQPZ79H.js +4 -0
  563. package/dist/ionic/p-BYEAtHr-.js +4 -0
  564. package/dist/ionic/p-BhamHSw3.js +4 -0
  565. package/dist/ionic/{p-DV3sJJW8.js → p-BvabGprD.js} +1 -1
  566. package/dist/ionic/p-C-94tAim.js +4 -0
  567. package/dist/ionic/{p-DipZFfzN.js → p-C-eHZMYE.js} +1 -1
  568. package/dist/ionic/p-CBR_W98Z.js +4 -0
  569. package/dist/ionic/{p-ClM02LPk.js → p-CBWAXjA5.js} +1 -1
  570. package/dist/ionic/p-CMRtMbJc.js +4 -0
  571. package/dist/ionic/p-CPcPmkGv.js +4 -0
  572. package/dist/ionic/p-CaRuIadB.js +4 -0
  573. package/dist/ionic/p-Cdjxf_yg.js +4 -0
  574. package/dist/ionic/p-ChhhtsGZ.js +5 -0
  575. package/dist/ionic/p-CzS1qWve.js +4 -0
  576. package/dist/ionic/p-D5t_-oMk.js +4 -0
  577. package/dist/ionic/p-D94_RztK.js +4 -0
  578. package/dist/ionic/p-DWCzVL3Y.js +4 -0
  579. package/dist/ionic/p-DjjfauRM.js +4 -0
  580. package/dist/ionic/p-DkUB-ROc.js +4 -0
  581. package/dist/ionic/p-Dn0mqQ_R.js +4 -0
  582. package/dist/ionic/p-Dojwmvde.js +4 -0
  583. package/dist/ionic/p-DplOqGUv.js +4 -0
  584. package/dist/ionic/p-Dst_XmZh.js +4 -0
  585. package/dist/ionic/p-T71k3C35.js +4 -0
  586. package/dist/ionic/p-TXPDHL13.js +4 -0
  587. package/dist/ionic/p-UIBJkZf8.js +4 -0
  588. package/dist/ionic/p-a438b193.entry.js +4 -0
  589. package/dist/ionic/p-babaaaa7.entry.js +4 -0
  590. package/dist/ionic/p-be08d500.entry.js +4 -0
  591. package/dist/ionic/p-be9a4f51.entry.js +4 -0
  592. package/dist/ionic/p-byZM6qHV.js +4 -0
  593. package/dist/ionic/p-c00d3092.entry.js +4 -0
  594. package/dist/ionic/p-c36dc8f5.entry.js +4 -0
  595. package/dist/ionic/p-c72a7e17.entry.js +4 -0
  596. package/dist/ionic/p-c8edd88c.entry.js +4 -0
  597. package/dist/ionic/p-ce0e380b.entry.js +4 -0
  598. package/dist/ionic/p-ce32912b.entry.js +4 -0
  599. package/dist/ionic/p-d07cf130.entry.js +4 -0
  600. package/dist/ionic/p-d27edeb3.entry.js +4 -0
  601. package/dist/ionic/p-d5d2c506.entry.js +4 -0
  602. package/dist/ionic/p-d5e31ca9.entry.js +4 -0
  603. package/dist/ionic/p-de91444f.entry.js +4 -0
  604. package/dist/ionic/p-ded69ceb.entry.js +4 -0
  605. package/dist/ionic/p-df72866d.entry.js +4 -0
  606. package/dist/ionic/p-e47e3151.entry.js +4 -0
  607. package/dist/ionic/p-e621e5e8.entry.js +4 -0
  608. package/dist/ionic/p-eea9cf93.entry.js +4 -0
  609. package/dist/ionic/p-f402f5a4.entry.js +4 -0
  610. package/dist/ionic/p-fe1bfbcf.entry.js +4 -0
  611. package/{components/p-9GFIh9p1.js → dist/ionic/p-ffb90460.entry.js} +1 -1
  612. package/dist/types/components/img/img.d.ts +2 -0
  613. package/dist/types/components/input/input.d.ts +12 -6
  614. package/dist/types/components/modal/modal-interface.d.ts +9 -0
  615. package/dist/types/components/modal/modal.d.ts +11 -4
  616. package/dist/types/components/nav/nav-interface.d.ts +0 -1
  617. package/dist/types/components/nav/nav.d.ts +2 -22
  618. package/dist/types/components/route/route.d.ts +1 -1
  619. package/dist/types/components/router-outlet/router-outlet.d.ts +7 -0
  620. package/dist/types/components/searchbar/searchbar.d.ts +1 -1
  621. package/dist/types/components/select/select-interface.d.ts +31 -0
  622. package/dist/types/components/select/select.d.ts +30 -6
  623. package/dist/types/components/select-option/select-option.d.ts +42 -1
  624. package/dist/types/components/textarea/textarea.d.ts +12 -5
  625. package/dist/types/components.d.ts +74 -311
  626. package/dist/types/index.d.ts +1 -1
  627. package/dist/types/interface.d.ts +0 -1
  628. package/dist/types/utils/config.d.ts +1 -8
  629. package/dist/types/utils/forms/index.d.ts +1 -0
  630. package/dist/types/utils/forms/start-container-controller.d.ts +34 -0
  631. package/dist/types/utils/logging/index.d.ts +2 -1
  632. package/dist/types/utils/overlay-control-label.d.ts +32 -0
  633. package/dist/types/utils/overlays.d.ts +11 -9
  634. package/dist/types/utils/sanitization/index.d.ts +58 -2
  635. package/dist/types/utils/select-option-render.d.ts +53 -0
  636. package/dist/types/utils/test/playwright/playwright-page.d.ts +1 -1
  637. package/dist/types/utils/test/playwright/testExpect.d.ts +1 -1
  638. package/hydrate/index.js +10660 -7305
  639. package/hydrate/index.mjs +10660 -7305
  640. package/package.json +55 -12
  641. package/components/ion-picker-legacy-column.d.ts +0 -11
  642. package/components/ion-picker-legacy-column.js +0 -4
  643. package/components/ion-picker-legacy.d.ts +0 -11
  644. package/components/ion-picker-legacy.js +0 -4
  645. package/components/p-0LM2oPMC.js +0 -4
  646. package/components/p-B21528L5.js +0 -4
  647. package/components/p-B2nSfLHH.js +0 -4
  648. package/components/p-B3qf4bEn.js +0 -4
  649. package/components/p-B9jFTlwE.js +0 -4
  650. package/components/p-BDd9Zrb9.js +0 -4
  651. package/components/p-BLmJ0zRm.js +0 -4
  652. package/components/p-BMYNBJgf.js +0 -4
  653. package/components/p-BRYd8D-I.js +0 -4
  654. package/components/p-BSEgsdFI.js +0 -4
  655. package/components/p-BTEOs1at.js +0 -4
  656. package/components/p-BTJrYwxN.js +0 -4
  657. package/components/p-BV-zKay-.js +0 -4
  658. package/components/p-BYRVyMu9.js +0 -4
  659. package/components/p-Bmq8qlkW.js +0 -4
  660. package/components/p-BuxQcfHK.js +0 -4
  661. package/components/p-Bz0dSlXZ.js +0 -4
  662. package/components/p-CHqRYvYm.js +0 -4
  663. package/components/p-CSZf8_j0.js +0 -4
  664. package/components/p-CTdRooFV.js +0 -4
  665. package/components/p-Cf2jSDS8.js +0 -4
  666. package/components/p-Cfx4M1Bn.js +0 -4
  667. package/components/p-CgkrslTX.js +0 -4
  668. package/components/p-CiCzYG2V.js +0 -4
  669. package/components/p-Ck0lEczL.js +0 -4
  670. package/components/p-CmR5uXej.js +0 -4
  671. package/components/p-CniZht3v.js +0 -4
  672. package/components/p-CsaojgEs.js +0 -4
  673. package/components/p-CtWGkNnJ.js +0 -4
  674. package/components/p-D13Eaw-8.js +0 -4
  675. package/components/p-D4FYu-4R.js +0 -4
  676. package/components/p-D6Ynv7Xh.js +0 -4
  677. package/components/p-DARjq3GM.js +0 -4
  678. package/components/p-DEZ2myA3.js +0 -4
  679. package/components/p-DOFCbuQR.js +0 -4
  680. package/components/p-DVe41iHI.js +0 -4
  681. package/components/p-DX5m9g56.js +0 -4
  682. package/components/p-DboHi2CL.js +0 -4
  683. package/components/p-DiVJyqlX.js +0 -4
  684. package/components/p-DmzFY5IC.js +0 -4
  685. package/components/p-DqZAXv2t.js +0 -4
  686. package/components/p-Dv8w0kqz.js +0 -4
  687. package/components/p-Dw7GNDKq.js +0 -4
  688. package/components/p-Dww01PNs.js +0 -4
  689. package/components/p-Gy276IJk.js +0 -4
  690. package/components/p-ZzLXTvyt.js +0 -4
  691. package/components/p-cyNmxje6.js +0 -4
  692. package/components/p-j5IxBIan.js +0 -4
  693. package/components/p-k_E4tX5Z.js +0 -4
  694. package/components/p-lVAbdiAu.js +0 -4
  695. package/components/p-o8OKV5aD.js +0 -4
  696. package/components/p-rCa2eL0j.js +0 -4
  697. package/dist/cjs/config-D6C-KlA9.js +0 -201
  698. package/dist/cjs/input.utils-DQaUGGed.js +0 -150
  699. package/dist/cjs/ion-datetime_3.cjs.entry.js +0 -3167
  700. package/dist/cjs/notch-controller-aiy8aQb-.js +0 -155
  701. package/dist/collection/components/picker-legacy/animations/ios.enter.js +0 -27
  702. package/dist/collection/components/picker-legacy/animations/ios.leave.js +0 -23
  703. package/dist/collection/components/picker-legacy/picker-interface.js +0 -1
  704. package/dist/collection/components/picker-legacy/picker.ios.css +0 -300
  705. package/dist/collection/components/picker-legacy/picker.js +0 -890
  706. package/dist/collection/components/picker-legacy/picker.md.css +0 -287
  707. package/dist/collection/components/picker-legacy-column/picker-column.ios.css +0 -231
  708. package/dist/collection/components/picker-legacy-column/picker-column.js +0 -422
  709. package/dist/collection/components/picker-legacy-column/picker-column.md.css +0 -222
  710. package/dist/collection/components/picker-legacy-column/test/test.utils.js +0 -43
  711. package/dist/esm/config-DQCONYYp.js +0 -195
  712. package/dist/esm/input.utils-Cd23Gdd1.js +0 -147
  713. package/dist/esm/ion-datetime_3.entry.js +0 -3163
  714. package/dist/esm/notch-controller-Doqis1td.js +0 -153
  715. package/dist/ionic/p-01f81ea5.entry.js +0 -4
  716. package/dist/ionic/p-0283ea73.entry.js +0 -4
  717. package/dist/ionic/p-02ecae65.entry.js +0 -4
  718. package/dist/ionic/p-0672f677.entry.js +0 -4
  719. package/dist/ionic/p-0c06fe60.entry.js +0 -4
  720. package/dist/ionic/p-0fa9c382.entry.js +0 -4
  721. package/dist/ionic/p-1af4d74c.entry.js +0 -4
  722. package/dist/ionic/p-1d7ef0d2.entry.js +0 -4
  723. package/dist/ionic/p-26f05d3a.entry.js +0 -4
  724. package/dist/ionic/p-27d30585.entry.js +0 -4
  725. package/dist/ionic/p-2bb2cb18.entry.js +0 -4
  726. package/dist/ionic/p-31e7bd05.entry.js +0 -4
  727. package/dist/ionic/p-32f53010.entry.js +0 -4
  728. package/dist/ionic/p-35eb8b5c.entry.js +0 -4
  729. package/dist/ionic/p-37e720da.entry.js +0 -4
  730. package/dist/ionic/p-3efa137b.entry.js +0 -4
  731. package/dist/ionic/p-432bd72c.entry.js +0 -4
  732. package/dist/ionic/p-47214c72.entry.js +0 -4
  733. package/dist/ionic/p-4e172429.entry.js +0 -4
  734. package/dist/ionic/p-5c3da84e.entry.js +0 -4
  735. package/dist/ionic/p-5d1da0a2.entry.js +0 -4
  736. package/dist/ionic/p-5d8082fe.entry.js +0 -4
  737. package/dist/ionic/p-613d3c43.entry.js +0 -4
  738. package/dist/ionic/p-616e4d4f.entry.js +0 -4
  739. package/dist/ionic/p-65d611b2.entry.js +0 -4
  740. package/dist/ionic/p-67806e3f.entry.js +0 -4
  741. package/dist/ionic/p-68cbb2fc.entry.js +0 -4
  742. package/dist/ionic/p-737ae9eb.entry.js +0 -4
  743. package/dist/ionic/p-7b0d6248.entry.js +0 -4
  744. package/dist/ionic/p-7e71e470.entry.js +0 -4
  745. package/dist/ionic/p-84d5ce05.entry.js +0 -4
  746. package/dist/ionic/p-85d49987.entry.js +0 -4
  747. package/dist/ionic/p-8945088b.entry.js +0 -4
  748. package/dist/ionic/p-8b155568.entry.js +0 -4
  749. package/dist/ionic/p-90267c4b.entry.js +0 -4
  750. package/dist/ionic/p-92ad8a67.entry.js +0 -4
  751. package/dist/ionic/p-9a97d4e0.entry.js +0 -4
  752. package/dist/ionic/p-9e4b0894.entry.js +0 -4
  753. package/dist/ionic/p-9eeaBrnk.js +0 -4
  754. package/dist/ionic/p-B2kaj8sx.js +0 -4
  755. package/dist/ionic/p-B4y7nxsg.js +0 -4
  756. package/dist/ionic/p-B8t9Ro6f.js +0 -4
  757. package/dist/ionic/p-BEOxsxBw.js +0 -4
  758. package/dist/ionic/p-BJ2NxSHp.js +0 -4
  759. package/dist/ionic/p-BLiL8g0v.js +0 -4
  760. package/dist/ionic/p-BTEOs1at.js +0 -4
  761. package/dist/ionic/p-BUFIpxKM.js +0 -4
  762. package/dist/ionic/p-BYRVyMu9.js +0 -4
  763. package/dist/ionic/p-C0eMdTCW.js +0 -4
  764. package/dist/ionic/p-CKvCXMs9.js +0 -4
  765. package/dist/ionic/p-CPTv7G9B.js +0 -4
  766. package/dist/ionic/p-CtWGkNnJ.js +0 -4
  767. package/dist/ionic/p-CxMyXUtt.js +0 -4
  768. package/dist/ionic/p-D13Eaw-8.js +0 -4
  769. package/dist/ionic/p-DCoy2elM.js +0 -4
  770. package/dist/ionic/p-DiVJyqlX.js +0 -4
  771. package/dist/ionic/p-DqN5EA2O.js +0 -4
  772. package/dist/ionic/p-Dr9fTCb1.js +0 -4
  773. package/dist/ionic/p-DzWaWHGc.js +0 -4
  774. package/dist/ionic/p-EkpneKVM.js +0 -4
  775. package/dist/ionic/p-Nqf6uvGh.js +0 -4
  776. package/dist/ionic/p-SNAkTDfm.js +0 -4
  777. package/dist/ionic/p-ab00b0d8.entry.js +0 -4
  778. package/dist/ionic/p-c2175309.entry.js +0 -4
  779. package/dist/ionic/p-c4b69d9b.entry.js +0 -4
  780. package/dist/ionic/p-c4d8641b.entry.js +0 -4
  781. package/dist/ionic/p-ce637936.entry.js +0 -4
  782. package/dist/ionic/p-da85e958.entry.js +0 -4
  783. package/dist/ionic/p-dfa8d673.entry.js +0 -4
  784. package/dist/ionic/p-e139357c.entry.js +0 -4
  785. package/dist/ionic/p-e7b7a7b1.entry.js +0 -4
  786. package/dist/ionic/p-f37ca594.entry.js +0 -4
  787. package/dist/ionic/p-f8dd336e.entry.js +0 -4
  788. package/dist/ionic/p-f9de757b.entry.js +0 -4
  789. package/dist/ionic/p-fe11cf51.entry.js +0 -4
  790. package/dist/ionic/p-mjKAFv89.js +0 -4
  791. package/dist/ionic/p-o8OKV5aD.js +0 -4
  792. package/dist/ionic/p-tcQvqkiX.js +0 -5
  793. package/dist/types/components/picker-legacy/animations/ios.enter.d.ts +0 -5
  794. package/dist/types/components/picker-legacy/animations/ios.leave.d.ts +0 -5
  795. package/dist/types/components/picker-legacy/picker-interface.d.ts +0 -52
  796. package/dist/types/components/picker-legacy/picker.d.ts +0 -158
  797. package/dist/types/components/picker-legacy-column/picker-column.d.ts +0 -46
  798. package/dist/types/components/picker-legacy-column/test/test.utils.d.ts +0 -9
  799. /package/components/{p-CO7fmmxt.js → p-LpMHEu3v.js} +0 -0
@@ -2,14 +2,18 @@
2
2
  * (C) Ionic http://ionicframework.com - MIT License
3
3
  */
4
4
  import { Build, Host, h, forceUpdate } from "@stencil/core";
5
- import { compareOptions, createNotchController, isOptionSelected, checkInvalidState } from "../../utils/forms/index";
5
+ import { ENABLE_HTML_CONTENT_DEFAULT } from "../../utils/config";
6
+ import { compareOptions, createNotchController, createStartContainerController, isOptionSelected, checkInvalidState, } from "../../utils/forms/index";
6
7
  import { focusVisibleElement, renderHiddenInput, inheritAttributes } from "../../utils/helpers";
7
8
  import { printIonWarning } from "../../utils/logging/index";
8
9
  import { actionSheetController, alertController, popoverController, modalController } from "../../utils/overlays";
9
10
  import { isRTL } from "../../utils/rtl/index";
11
+ import { reflectPropertiesToAttributes, sanitizeDOMTree } from "../../utils/sanitization/index";
12
+ import { createSlotMutationController } from "../../utils/slot-mutation-controller";
10
13
  import { createColorClasses, hostContext } from "../../utils/theme";
11
14
  import { watchForOptions } from "../../utils/watch-options";
12
15
  import { caretDownSharp, chevronExpand } from "ionicons/icons";
16
+ import { config } from "../../global/config";
13
17
  import { getIonMode } from "../../global/ionic-global";
14
18
  // TODO(FW-2832): types
15
19
  /**
@@ -29,145 +33,244 @@ import { getIonMode } from "../../global/ionic-global";
29
33
  * @part error-text - Supporting text displayed beneath the select when the select is invalid and touched.
30
34
  * @part bottom - The container element for helper text, error text, and counter.
31
35
  * @part wrapper - The clickable label element that wraps the entire form field (label text, slots, selected values or placeholder, and toggle icons).
32
- * @part inner - The inner element of the wrapper that manages the slots, selected values or placeholder, and toggle icons.
36
+ * @part start - The wrapper element for the content in the start slot.
37
+ * @part control - The wrapper element containing the label and native select control. When the label is not floating or stacked, this part also contains the dropdown icon.
38
+ * @part end - The wrapper element for the content in the end slot. When the label is floating or stacked, this part also contains the dropdown icon.
33
39
  */
34
40
  export class Select {
35
- constructor() {
36
- this.inputId = `ion-sel-${selectIds++}`;
37
- this.helperTextId = `${this.inputId}-helper-text`;
38
- this.errorTextId = `${this.inputId}-error-text`;
39
- this.inheritedAttributes = {};
40
- this.isExpanded = false;
41
- /**
42
- * The `hasFocus` state ensures the focus class is
43
- * added regardless of how the element is focused.
44
- * The `ion-focused` class only applies when focused
45
- * via tabbing, not by clicking.
46
- * The `has-focus` logic was added to ensure the class
47
- * is applied in both cases.
48
- */
49
- this.hasFocus = false;
50
- /**
51
- * Track validation state for proper aria-live announcements.
52
- */
53
- this.isInvalid = false;
54
- /**
55
- * The text to display on the cancel button.
56
- */
57
- this.cancelText = 'Cancel';
58
- /**
59
- * If `true`, the user cannot interact with the select.
60
- */
61
- this.disabled = false;
62
- /**
63
- * The interface the select should use: `action-sheet`, `popover`, `alert`, or `modal`.
64
- */
65
- this.interface = 'alert';
66
- /**
67
- * Any additional options that the `alert`, `action-sheet` or `popover` interface
68
- * can take. See the [ion-alert docs](./alert), the
69
- * [ion-action-sheet docs](./action-sheet), the
70
- * [ion-popover docs](./popover), and the [ion-modal docs](./modal) for the
71
- * create options for each interface.
72
- *
73
- * Note: `interfaceOptions` will not override `inputs` or `buttons` with the `alert` interface.
74
- */
75
- this.interfaceOptions = {};
76
- /**
77
- * Where to place the label relative to the select.
78
- * `"start"`: The label will appear to the left of the select in LTR and to the right in RTL.
79
- * `"end"`: The label will appear to the right of the select in LTR and to the left in RTL.
80
- * `"floating"`: The label will appear smaller and above the select when the select is focused or it has a value. Otherwise it will appear on top of the select.
81
- * `"stacked"`: The label will appear smaller and above the select regardless even when the select is blurred or has no value.
82
- * `"fixed"`: The label has the same behavior as `"start"` except it also has a fixed width. Long text will be truncated with ellipses ("...").
83
- * When using `"floating"` or `"stacked"` we recommend initializing the select with either a `value` or a `placeholder`.
84
- */
85
- this.labelPlacement = 'start';
86
- /**
87
- * If `true`, the select can accept multiple values.
88
- */
89
- this.multiple = false;
90
- /**
91
- * The name of the control, which is submitted with the form data.
92
- */
93
- this.name = this.inputId;
94
- /**
95
- * The text to display on the ok button.
96
- */
97
- this.okText = 'OK';
98
- /**
99
- * If true, screen readers will announce it as a required field. This property
100
- * works only for accessibility purposes, it will not prevent the form from
101
- * submitting if the value is invalid.
102
- */
103
- this.required = false;
104
- this.onClick = (ev) => {
105
- const target = ev.target;
106
- const closestSlot = target.closest('[slot="start"], [slot="end"]');
107
- if (target === this.el || closestSlot === null) {
108
- this.setFocus();
109
- this.open(ev);
110
- }
111
- else {
112
- /**
113
- * Prevent clicks to the start/end slots from opening the select.
114
- * We ensure the target isn't this element in case the select is slotted
115
- * in, for example, an item. This would prevent the select from ever
116
- * being opened since the element itself has slot="start"/"end".
117
- *
118
- * Clicking a slotted element also causes a click
119
- * on the <label> element (since it wraps the slots).
120
- * Clicking <label> dispatches another click event on
121
- * the native form control that then bubbles up to this
122
- * listener. This additional event targets the host
123
- * element, so the select overlay is opened.
124
- *
125
- * When the slotted elements are clicked (and therefore
126
- * the ancestor <label> element) we want to prevent the label
127
- * from dispatching another click event.
128
- *
129
- * Do not call stopPropagation() because this will cause
130
- * click handlers on the slotted elements to never fire in React.
131
- * When developers do onClick in React a native "click" listener
132
- * is added on the root element, not the slotted element. When that
133
- * native click listener fires, React then dispatches the synthetic
134
- * click event on the slotted element. However, if stopPropagation
135
- * is called then the native click event will never bubble up
136
- * to the root element.
137
- */
138
- ev.preventDefault();
139
- }
140
- };
141
- this.onFocus = () => {
142
- this.hasFocus = true;
143
- this.ionFocus.emit();
144
- };
145
- this.onBlur = () => {
146
- this.hasFocus = false;
147
- this.ionBlur.emit();
148
- };
149
- /**
150
- * Stops propagation when the label is clicked,
151
- * otherwise, two clicks will be triggered.
152
- */
153
- this.onLabelClick = (ev) => {
154
- // Only stop propagation if the click was directly on the label
155
- // and not on the input or other child elements
156
- if (ev.target === ev.currentTarget) {
157
- ev.stopPropagation();
158
- }
159
- };
160
- }
41
+ inputId = `ion-sel-${selectIds++}`;
42
+ helperTextId = `${this.inputId}-helper-text`;
43
+ errorTextId = `${this.inputId}-error-text`;
44
+ overlay;
45
+ focusEl;
46
+ mutationO;
47
+ inheritedAttributes = {};
48
+ slotMutationController;
49
+ nativeWrapperEl;
50
+ notchSpacerEl;
51
+ validationObserver;
52
+ notchController;
53
+ startContainerController;
54
+ startContainerEl;
55
+ customHTMLEnabled = config.get('innerHTMLTemplatesEnabled', ENABLE_HTML_CONTENT_DEFAULT);
56
+ el;
57
+ isExpanded = false;
58
+ /**
59
+ * The `hasFocus` state ensures the focus class is
60
+ * added regardless of how the element is focused.
61
+ * The `ion-focused` class only applies when focused
62
+ * via tabbing, not by clicking.
63
+ * The `has-focus` logic was added to ensure the class
64
+ * is applied in both cases.
65
+ */
66
+ hasFocus = false;
67
+ /**
68
+ * Track validation state for proper aria-live announcements.
69
+ */
70
+ isInvalid = false;
71
+ hintTextId;
72
+ /**
73
+ * The text to display on the cancel button.
74
+ */
75
+ cancelText = 'Cancel';
76
+ /**
77
+ * The color to use from your application's color palette.
78
+ * Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`.
79
+ * For more information on colors, see [theming](/docs/theming/basics).
80
+ *
81
+ * This property is only available when using the modern select syntax.
82
+ */
83
+ color;
84
+ /**
85
+ * This property allows developers to specify a custom function or property
86
+ * name for comparing objects when determining the selected option in the
87
+ * ion-select. When not specified, the default behavior will use strict
88
+ * equality (===) for comparison.
89
+ */
90
+ compareWith;
91
+ /**
92
+ * If `true`, the user cannot interact with the select.
93
+ */
94
+ disabled = false;
95
+ /**
96
+ * The fill for the item. If `"solid"` the item will have a background. If
97
+ * `"outline"` the item will be transparent with a border. Only available in `md` mode.
98
+ */
99
+ fill;
100
+ /**
101
+ * Text that is placed under the select and displayed when an error is detected.
102
+ */
103
+ errorText;
104
+ /**
105
+ * Text that is placed under the select and displayed when no error is detected.
106
+ */
107
+ helperText;
108
+ /**
109
+ * The interface the select should use: `action-sheet`, `popover`, `alert`, or `modal`.
110
+ */
111
+ interface = 'alert';
112
+ /**
113
+ * Any additional options that the `alert`, `action-sheet` or `popover` interface
114
+ * can take. See the [ion-alert docs](./alert), the
115
+ * [ion-action-sheet docs](./action-sheet), the
116
+ * [ion-popover docs](./popover), and the [ion-modal docs](./modal) for the
117
+ * create options for each interface.
118
+ *
119
+ * Note: `interfaceOptions` will not override `inputs` or `buttons` with the `alert` interface.
120
+ */
121
+ interfaceOptions = {};
122
+ /**
123
+ * How to pack the label and select within a line.
124
+ * `justify` does not apply when the label and select
125
+ * are on different lines when `labelPlacement` is set to
126
+ * `"floating"` or `"stacked"`.
127
+ * `"start"`: The label and select will appear on the left in LTR and
128
+ * on the right in RTL.
129
+ * `"end"`: The label and select will appear on the right in LTR and
130
+ * on the left in RTL.
131
+ * `"space-between"`: The label and select will appear on opposite
132
+ * ends of the line with space between the two elements.
133
+ */
134
+ justify;
135
+ /**
136
+ * The visible label associated with the select.
137
+ *
138
+ * Use this if you need to render a plaintext label.
139
+ *
140
+ * The `label` property will take priority over the `label` slot if both are used.
141
+ */
142
+ label;
143
+ /**
144
+ * Where to place the label relative to the select.
145
+ * `"start"`: The label will appear to the left of the select in LTR and to the right in RTL.
146
+ * `"end"`: The label will appear to the right of the select in LTR and to the left in RTL.
147
+ * `"floating"`: The label will appear smaller and above the select when the select is focused or it has a value. Otherwise it will appear on top of the select.
148
+ * `"stacked"`: The label will appear smaller and above the select regardless even when the select is blurred or has no value.
149
+ * `"fixed"`: The label has the same behavior as `"start"` except it also has a fixed width. Long text will be truncated with ellipses ("...").
150
+ * When using `"floating"` or `"stacked"` we recommend initializing the select with either a `value` or a `placeholder`.
151
+ */
152
+ labelPlacement = 'start';
153
+ /**
154
+ * If `true`, the select can accept multiple values.
155
+ */
156
+ multiple = false;
157
+ /**
158
+ * The name of the control, which is submitted with the form data.
159
+ */
160
+ name = this.inputId;
161
+ /**
162
+ * The text to display on the ok button.
163
+ */
164
+ okText = 'OK';
165
+ /**
166
+ * The text to display when the select is empty.
167
+ */
168
+ placeholder;
169
+ /**
170
+ * The text to display instead of the selected option's value.
171
+ */
172
+ selectedText;
173
+ /**
174
+ * The toggle icon to use. Defaults to `chevronExpand` for `ios` mode,
175
+ * or `caretDownSharp` for `md` mode.
176
+ */
177
+ toggleIcon;
178
+ /**
179
+ * The toggle icon to show when the select is open. If defined, the icon
180
+ * rotation behavior in `md` mode will be disabled. If undefined, `toggleIcon`
181
+ * will be used for when the select is both open and closed.
182
+ */
183
+ expandedIcon;
184
+ /**
185
+ * The shape of the select. If "round" it will have an increased border radius.
186
+ */
187
+ shape;
188
+ /**
189
+ * The value of the select.
190
+ */
191
+ value;
192
+ /**
193
+ * If true, screen readers will announce it as a required field. This property
194
+ * works only for accessibility purposes, it will not prevent the form from
195
+ * submitting if the value is invalid.
196
+ */
197
+ required = false;
198
+ /**
199
+ * Emitted when the value has changed.
200
+ *
201
+ * This event will not emit when programmatically setting the `value` property.
202
+ */
203
+ ionChange;
204
+ /**
205
+ * Emitted when the selection is cancelled.
206
+ */
207
+ ionCancel;
208
+ /**
209
+ * Emitted when the overlay is dismissed.
210
+ */
211
+ ionDismiss;
212
+ /**
213
+ * Emitted when the select has focus.
214
+ */
215
+ ionFocus;
216
+ /**
217
+ * Emitted when the select loses focus.
218
+ */
219
+ ionBlur;
220
+ /**
221
+ * Emitted when the styles change.
222
+ * @internal
223
+ */
224
+ ionStyle;
161
225
  styleChanged() {
162
226
  this.emitStyle();
163
227
  }
164
228
  setValue(value) {
229
+ if (this.isValueEqual(this.value, value)) {
230
+ return;
231
+ }
165
232
  this.value = value;
166
233
  this.ionChange.emit({ value });
167
234
  }
235
+ isValueEqual(currentValue, newValue) {
236
+ if (this.multiple) {
237
+ const currentArr = Array.isArray(currentValue) ? currentValue : [];
238
+ const newArr = Array.isArray(newValue) ? newValue : [];
239
+ if (currentArr.length !== newArr.length) {
240
+ return false;
241
+ }
242
+ // Multiset compare: each new value must match a distinct current value.
243
+ // A plain `every(isOptionSelected)` would accept ['a','a'] as equal to
244
+ // ['a','b'] when both 'a' and 'b' map to options whose values overlap.
245
+ const remaining = currentArr.slice();
246
+ return newArr.every((val) => {
247
+ const idx = remaining.findIndex((c) => compareOptions(c, val, this.compareWith));
248
+ if (idx === -1) {
249
+ return false;
250
+ }
251
+ remaining.splice(idx, 1);
252
+ return true;
253
+ });
254
+ }
255
+ if (currentValue == null && newValue == null) {
256
+ return true;
257
+ }
258
+ if (currentValue == null || newValue == null) {
259
+ return false;
260
+ }
261
+ return compareOptions(currentValue, newValue, this.compareWith);
262
+ }
168
263
  async connectedCallback() {
169
264
  const { el } = this;
265
+ this.slotMutationController = createSlotMutationController(el, ['label', 'start', 'end'], () => {
266
+ this.startContainerController?.calculateStartContainerWidth();
267
+ forceUpdate(this);
268
+ });
170
269
  this.notchController = createNotchController(el, () => this.notchSpacerEl, () => this.labelSlot);
270
+ this.startContainerController = createStartContainerController(el, () => this.startContainerEl, () => {
271
+ return Build.isBrowser && getIonMode(this) === 'md' && this.fill === 'outline';
272
+ });
273
+ this.startContainerController.calculateStartContainerWidth();
171
274
  this.updateOverlayOptions();
172
275
  this.emitStyle();
173
276
  this.mutationO = watchForOptions(this.el, 'ion-select-option', async () => {
@@ -239,10 +342,18 @@ export class Select {
239
342
  this.mutationO.disconnect();
240
343
  this.mutationO = undefined;
241
344
  }
345
+ if (this.slotMutationController) {
346
+ this.slotMutationController.destroy();
347
+ this.slotMutationController = undefined;
348
+ }
242
349
  if (this.notchController) {
243
350
  this.notchController.destroy();
244
351
  this.notchController = undefined;
245
352
  }
353
+ if (this.startContainerController) {
354
+ this.startContainerController.destroy();
355
+ this.startContainerController = undefined;
356
+ }
246
357
  // Clean up validation observer to prevent memory leaks.
247
358
  if (this.validationObserver) {
248
359
  this.validationObserver.disconnect();
@@ -399,10 +510,11 @@ export class Select {
399
510
  .join(' ');
400
511
  const optClass = `${OPTION_CLASS} ${copyClasses}`;
401
512
  const isSelected = isOptionSelected(selectValue, value, this.compareWith);
513
+ const { content, startContent, endContent } = extractOptionContent(option, this.customHTMLEnabled);
402
514
  return {
403
- role: isSelected ? 'selected' : '',
404
- text: option.textContent,
515
+ text: content ?? '',
405
516
  cssClass: optClass,
517
+ disabled: option.disabled,
406
518
  handler: () => {
407
519
  this.setValue(value);
408
520
  },
@@ -410,6 +522,9 @@ export class Select {
410
522
  'aria-checked': isSelected ? 'true' : 'false',
411
523
  role: 'radio',
412
524
  },
525
+ startContent,
526
+ endContent,
527
+ description: option.description,
413
528
  };
414
529
  });
415
530
  // Add "cancel" button
@@ -430,13 +545,19 @@ export class Select {
430
545
  .filter((cls) => cls !== 'hydrated')
431
546
  .join(' ');
432
547
  const optClass = `${OPTION_CLASS} ${copyClasses}`;
548
+ const { content, startContent, endContent } = extractOptionContent(option, this.customHTMLEnabled);
433
549
  return {
434
550
  type: inputType,
435
551
  cssClass: optClass,
436
- label: option.textContent || '',
552
+ label: content ?? '',
437
553
  value,
438
554
  checked: isOptionSelected(selectValue, value, this.compareWith),
439
555
  disabled: option.disabled,
556
+ startContent,
557
+ endContent,
558
+ description: option.description,
559
+ labelPlacement: option.labelPlacement,
560
+ justify: option.justify,
440
561
  };
441
562
  });
442
563
  return alertInputs;
@@ -449,8 +570,9 @@ export class Select {
449
570
  .filter((cls) => cls !== 'hydrated')
450
571
  .join(' ');
451
572
  const optClass = `${OPTION_CLASS} ${copyClasses}`;
573
+ const { content, startContent, endContent } = extractOptionContent(option, this.customHTMLEnabled);
452
574
  return {
453
- text: option.textContent || '',
575
+ text: content ?? '',
454
576
  cssClass: optClass,
455
577
  value,
456
578
  checked: isOptionSelected(selectValue, value, this.compareWith),
@@ -461,6 +583,11 @@ export class Select {
461
583
  this.close();
462
584
  }
463
585
  },
586
+ startContent,
587
+ endContent,
588
+ description: option.description,
589
+ labelPlacement: option.labelPlacement,
590
+ justify: option.justify,
464
591
  };
465
592
  });
466
593
  return popoverOptions;
@@ -489,28 +616,43 @@ export class Select {
489
616
  */
490
617
  }
491
618
  else {
492
- event = Object.assign(Object.assign({}, ev), { detail: {
619
+ event = {
620
+ ...ev,
621
+ detail: {
493
622
  ionShadowTarget: this.nativeWrapperEl,
494
- } });
623
+ },
624
+ };
495
625
  }
496
- const popoverOpts = Object.assign(Object.assign({ mode,
497
- event, alignment: 'center', size,
498
- showBackdrop }, interfaceOptions), { component: 'ion-select-popover', cssClass: ['select-popover', interfaceOptions.cssClass], componentProps: {
626
+ const options = this.createOverlaySelectOptions(this.childOpts, value);
627
+ const hasRichContent = options.some((opt) => Boolean(opt.startContent) || Boolean(opt.endContent) || Boolean(opt.description));
628
+ const popoverOpts = {
629
+ mode,
630
+ event,
631
+ alignment: 'center',
632
+ size,
633
+ showBackdrop,
634
+ ...interfaceOptions,
635
+ component: 'ion-select-popover',
636
+ cssClass: [
637
+ 'select-popover',
638
+ hasRichContent ? 'select-popover-rich-content' : undefined,
639
+ interfaceOptions.cssClass,
640
+ ],
641
+ componentProps: {
499
642
  header: interfaceOptions.header,
500
643
  subHeader: interfaceOptions.subHeader,
501
644
  message: interfaceOptions.message,
502
645
  multiple,
503
646
  value,
504
- options: this.createOverlaySelectOptions(this.childOpts, value),
505
- } });
647
+ options,
648
+ },
649
+ };
506
650
  /**
507
651
  * Workaround for Stencil to autodefine
508
652
  * ion-select-popover and ion-popover when
509
653
  * using Custom Elements build.
510
654
  */
511
- // eslint-disable-next-line
512
655
  if (false) {
513
- // eslint-disable-next-line
514
656
  // @ts-ignore
515
657
  document.createElement('ion-select-popover');
516
658
  document.createElement('ion-popover');
@@ -520,15 +662,18 @@ export class Select {
520
662
  async openActionSheet() {
521
663
  const mode = getIonMode(this);
522
664
  const interfaceOptions = this.interfaceOptions;
523
- const actionSheetOpts = Object.assign(Object.assign({ mode }, interfaceOptions), { buttons: this.createActionSheetButtons(this.childOpts, this.value), cssClass: ['select-action-sheet', interfaceOptions.cssClass] });
665
+ const actionSheetOpts = {
666
+ mode,
667
+ ...interfaceOptions,
668
+ buttons: this.createActionSheetButtons(this.childOpts, this.value),
669
+ cssClass: ['select-action-sheet', interfaceOptions.cssClass],
670
+ };
524
671
  /**
525
672
  * Workaround for Stencil to autodefine
526
673
  * ion-action-sheet when
527
674
  * using Custom Elements build.
528
675
  */
529
- // eslint-disable-next-line
530
676
  if (false) {
531
- // eslint-disable-next-line
532
677
  // @ts-ignore
533
678
  document.createElement('ion-action-sheet');
534
679
  }
@@ -538,7 +683,12 @@ export class Select {
538
683
  const interfaceOptions = this.interfaceOptions;
539
684
  const inputType = this.multiple ? 'checkbox' : 'radio';
540
685
  const mode = getIonMode(this);
541
- const alertOpts = Object.assign(Object.assign({ mode }, interfaceOptions), { header: interfaceOptions.header ? interfaceOptions.header : this.labelText, inputs: this.createAlertInputs(this.childOpts, inputType, this.value), buttons: [
686
+ const alertOpts = {
687
+ mode,
688
+ ...interfaceOptions,
689
+ header: interfaceOptions.header ? interfaceOptions.header : this.labelText,
690
+ inputs: this.createAlertInputs(this.childOpts, inputType, this.value),
691
+ buttons: [
542
692
  {
543
693
  text: this.cancelText,
544
694
  role: 'cancel',
@@ -552,19 +702,19 @@ export class Select {
552
702
  this.setValue(selectedValues);
553
703
  },
554
704
  },
555
- ], cssClass: [
705
+ ],
706
+ cssClass: [
556
707
  'select-alert',
557
708
  interfaceOptions.cssClass,
558
709
  this.multiple ? 'multiple-select-alert' : 'single-select-alert',
559
- ] });
710
+ ],
711
+ };
560
712
  /**
561
713
  * Workaround for Stencil to autodefine
562
714
  * ion-alert when
563
715
  * using Custom Elements build.
564
716
  */
565
- // eslint-disable-next-line
566
717
  if (false) {
567
- // eslint-disable-next-line
568
718
  // @ts-ignore
569
719
  document.createElement('ion-alert');
570
720
  }
@@ -573,21 +723,25 @@ export class Select {
573
723
  openModal() {
574
724
  const { multiple, value, interfaceOptions } = this;
575
725
  const mode = getIonMode(this);
576
- const modalOpts = Object.assign(Object.assign({}, interfaceOptions), { mode, cssClass: ['select-modal', interfaceOptions.cssClass], component: 'ion-select-modal', componentProps: {
726
+ const modalOpts = {
727
+ ...interfaceOptions,
728
+ mode,
729
+ cssClass: ['select-modal', interfaceOptions.cssClass],
730
+ component: 'ion-select-modal',
731
+ componentProps: {
577
732
  header: interfaceOptions.header,
578
733
  cancelText: this.cancelText,
579
734
  multiple,
580
735
  value,
581
736
  options: this.createOverlaySelectOptions(this.childOpts, value),
582
- } });
737
+ },
738
+ };
583
739
  /**
584
740
  * Workaround for Stencil to autodefine
585
741
  * ion-select-modal and ion-modal when
586
742
  * using Custom Elements build.
587
743
  */
588
- // eslint-disable-next-line
589
744
  if (false) {
590
- // eslint-disable-next-line
591
745
  // @ts-ignore
592
746
  document.createElement('ion-select-modal');
593
747
  document.createElement('ion-modal');
@@ -628,12 +782,18 @@ export class Select {
628
782
  }
629
783
  return;
630
784
  }
631
- getText() {
785
+ /**
786
+ * Returns the text to display in the select based on the selected value.
787
+ *
788
+ * @param useHTML If `true`, the returned text will include any custom HTML content from the selected option. If `false`, the returned text will be plain text without any HTML. Defaults to `false`.
789
+ * @returns The text to display in the select, either with or without HTML based on the `useHTML` parameter.
790
+ */
791
+ getText(useHTML = false) {
632
792
  const selectedText = this.selectedText;
633
793
  if (selectedText != null && selectedText !== '') {
634
794
  return selectedText;
635
795
  }
636
- return generateText(this.childOpts, this.value, this.compareWith);
796
+ return generateText(this.childOpts, this.value, this.compareWith, useHTML);
637
797
  }
638
798
  setFocus() {
639
799
  if (this.focusEl) {
@@ -647,6 +807,51 @@ export class Select {
647
807
  };
648
808
  this.ionStyle.emit(style);
649
809
  }
810
+ onClick = (ev) => {
811
+ const target = ev.target;
812
+ const closestSlot = target.closest('[slot="start"], [slot="end"]');
813
+ if (target === this.el || closestSlot === null) {
814
+ this.setFocus();
815
+ this.open(ev);
816
+ }
817
+ else {
818
+ /**
819
+ * Prevent clicks to the start/end slots from opening the select.
820
+ * We ensure the target isn't this element in case the select is slotted
821
+ * in, for example, an item. This would prevent the select from ever
822
+ * being opened since the element itself has slot="start"/"end".
823
+ *
824
+ * Clicking a slotted element also causes a click
825
+ * on the <label> element (since it wraps the slots).
826
+ * Clicking <label> dispatches another click event on
827
+ * the native form control that then bubbles up to this
828
+ * listener. This additional event targets the host
829
+ * element, so the select overlay is opened.
830
+ *
831
+ * When the slotted elements are clicked (and therefore
832
+ * the ancestor <label> element) we want to prevent the label
833
+ * from dispatching another click event.
834
+ *
835
+ * Do not call stopPropagation() because this will cause
836
+ * click handlers on the slotted elements to never fire in React.
837
+ * When developers do onClick in React a native "click" listener
838
+ * is added on the root element, not the slotted element. When that
839
+ * native click listener fires, React then dispatches the synthetic
840
+ * click event on the slotted element. However, if stopPropagation
841
+ * is called then the native click event will never bubble up
842
+ * to the root element.
843
+ */
844
+ ev.preventDefault();
845
+ }
846
+ };
847
+ onFocus = () => {
848
+ this.hasFocus = true;
849
+ this.ionFocus.emit();
850
+ };
851
+ onBlur = () => {
852
+ this.hasFocus = false;
853
+ this.ionBlur.emit();
854
+ };
650
855
  renderLabel() {
651
856
  const { label } = this;
652
857
  return (h("div", { class: {
@@ -655,8 +860,8 @@ export class Select {
655
860
  }, part: "label" }, label === undefined ? h("slot", { name: "label" }) : h("div", { class: "label-text" }, label)));
656
861
  }
657
862
  componentDidRender() {
658
- var _a;
659
- (_a = this.notchController) === null || _a === void 0 ? void 0 : _a.calculateNotchWidth();
863
+ this.notchController?.calculateNotchWidth();
864
+ this.startContainerController?.calculateStartContainerWidth();
660
865
  }
661
866
  /**
662
867
  * Gets any content passed into the `label` slot,
@@ -675,33 +880,64 @@ export class Select {
675
880
  return this.label !== undefined || this.labelSlot !== null;
676
881
  }
677
882
  /**
678
- * Renders the border container
679
- * when fill="outline".
883
+ * Stops propagation for re-dispatched clicks (when already expanded) to
884
+ * prevent double-click events. Allows initial button clicks (from keyboard
885
+ * or mouse) and slotted content clicks to propagate so event delegation
886
+ * works for parent handlers.
680
887
  */
681
- renderLabelContainer() {
682
- const mode = getIonMode(this);
683
- const hasOutlineFill = mode === 'md' && this.fill === 'outline';
684
- if (hasOutlineFill) {
685
- /**
686
- * The outline fill has a special outline
687
- * that appears around the select and the label.
688
- * Certain stacked and floating label placements cause the
689
- * label to translate up and create a "cut out"
690
- * inside of that border by using the notch-spacer element.
691
- */
692
- return [
693
- h("div", { class: "select-outline-container" }, h("div", { class: "select-outline-start" }), h("div", { class: {
694
- 'select-outline-notch': true,
695
- 'select-outline-notch-hidden': !this.hasLabel,
696
- } }, h("div", { class: "notch-spacer", "aria-hidden": "true", ref: (el) => (this.notchSpacerEl = el) }, this.label)), h("div", { class: "select-outline-end" })),
697
- this.renderLabel(),
698
- ];
888
+ onLabelClick = (ev) => {
889
+ if (ev.target === this.focusEl && this.isExpanded) {
890
+ ev.stopPropagation();
699
891
  }
700
- /**
701
- * If not using the outline style,
702
- * we can render just the label.
703
- */
704
- return this.renderLabel();
892
+ };
893
+ /**
894
+ * Renders the outline border with a notch for the label.
895
+ */
896
+ renderOutlineContainer() {
897
+ return (h("div", { class: "select-outline-container" }, h("div", { class: "select-outline-start" }), h("div", { class: {
898
+ 'select-outline-notch': true,
899
+ 'select-outline-notch-hidden': !this.hasLabel,
900
+ } }, h("div", { class: "notch-spacer", "aria-hidden": "true", ref: (el) => (this.notchSpacerEl = el) }, this.label)), h("div", { class: "select-outline-end" })));
901
+ }
902
+ /**
903
+ * Wraps text nodes in the select text with span elements
904
+ * so spacing can be added between elements without
905
+ * changing the display to prevent losing the ellipses
906
+ * behavior.
907
+ *
908
+ * Only wraps when the string contains HTML elements
909
+ * alongside text.
910
+ */
911
+ wrapSelectTextNodes(html) {
912
+ const temp = document.createElement('div');
913
+ temp.innerHTML = html;
914
+ const hasElements = Array.from(temp.childNodes).some((n) => n.nodeType === Node.ELEMENT_NODE);
915
+ // Return the plain text
916
+ if (!hasElements) {
917
+ return html;
918
+ }
919
+ Array.from(temp.childNodes).forEach((node) => {
920
+ if (node.nodeType === Node.TEXT_NODE && node.textContent?.trim()) {
921
+ const text = node.textContent;
922
+ /**
923
+ * Split comma separator from the text content
924
+ * e.g., ", Bacon" becomes ", " text node + <span>Bacon</span>.
925
+ */
926
+ const commaMatch = text.match(/^(,\s*)(.*)/);
927
+ if (commaMatch) {
928
+ const commaNode = document.createTextNode(commaMatch[1]);
929
+ const wrapper = document.createElement('span');
930
+ wrapper.textContent = commaMatch[2];
931
+ node.parentNode?.replaceChild(wrapper, node);
932
+ wrapper.parentNode?.insertBefore(commaNode, wrapper);
933
+ return;
934
+ }
935
+ const wrapper = document.createElement('span');
936
+ node.parentNode?.replaceChild(wrapper, node);
937
+ wrapper.appendChild(node);
938
+ }
939
+ });
940
+ return temp.innerHTML;
705
941
  }
706
942
  /**
707
943
  * Renders either the placeholder
@@ -710,7 +946,7 @@ export class Select {
710
946
  */
711
947
  renderSelectText() {
712
948
  const { placeholder } = this;
713
- const displayValue = this.getText();
949
+ const displayValue = this.getText(true);
714
950
  let addPlaceholderClass = false;
715
951
  let selectText = displayValue;
716
952
  if (selectText === '' && placeholder !== undefined) {
@@ -722,6 +958,10 @@ export class Select {
722
958
  'select-placeholder': addPlaceholderClass,
723
959
  };
724
960
  const textPart = addPlaceholderClass ? 'placeholder' : 'text';
961
+ if (this.customHTMLEnabled) {
962
+ const wrapped = this.wrapSelectTextNodes(selectText);
963
+ return h("div", { "aria-hidden": "true", class: selectTextClasses, part: textPart, innerHTML: wrapped });
964
+ }
725
965
  return (h("div", { "aria-hidden": "true", class: selectTextClasses, part: textPart }, selectText));
726
966
  }
727
967
  /**
@@ -737,16 +977,16 @@ export class Select {
737
977
  }
738
978
  else {
739
979
  const defaultIcon = mode === 'ios' ? chevronExpand : caretDownSharp;
740
- icon = toggleIcon !== null && toggleIcon !== void 0 ? toggleIcon : defaultIcon;
980
+ icon = toggleIcon ?? defaultIcon;
741
981
  }
742
982
  return h("ion-icon", { class: "select-icon", part: "icon", "aria-hidden": "true", icon: icon });
743
983
  }
744
984
  get ariaLabel() {
745
- var _a;
746
985
  const { placeholder, inheritedAttributes } = this;
986
+ // Get the plain text from the selected text
747
987
  const displayValue = this.getText();
748
988
  // The aria label should be preferred over visible text if both are specified
749
- const definedLabel = (_a = inheritedAttributes['aria-label']) !== null && _a !== void 0 ? _a : this.labelText;
989
+ const definedLabel = inheritedAttributes['aria-label'] ?? this.labelText;
750
990
  /**
751
991
  * If developer has specified a placeholder
752
992
  * and there is nothing selected, the selectText
@@ -817,28 +1057,10 @@ export class Select {
817
1057
  const inItem = hostContext('ion-item', this.el);
818
1058
  const shouldRenderHighlight = mode === 'md' && fill !== 'outline' && !inItem;
819
1059
  const hasValue = this.hasValue();
820
- const hasStartEndSlots = el.querySelector('[slot="start"], [slot="end"]') !== null;
1060
+ const hasOutlineFill = mode === 'md' && fill === 'outline';
821
1061
  renderHiddenInput(true, el, name, parseValue(value), disabled);
822
- /**
823
- * If the label is stacked, it should always sit above the select.
824
- * For floating labels, the label should move above the select if
825
- * the select has a value, is open, or has anything in either
826
- * the start or end slot.
827
- *
828
- * If there is content in the start slot, the label would overlap
829
- * it if not forced to float. This is also applied to the end slot
830
- * because with the default or solid fills, the select is not
831
- * vertically centered in the container, but the label is. This
832
- * causes the slots and label to appear vertically offset from each
833
- * other when the label isn't floating above the input. This doesn't
834
- * apply to the outline fill, but this was not accounted for to keep
835
- * things consistent.
836
- *
837
- * TODO(FW-5592): Remove hasStartEndSlots condition
838
- */
839
- const labelShouldFloat = labelPlacement === 'stacked' ||
840
- (labelPlacement === 'floating' && (hasValue || hasFocus || isExpanded || hasStartEndSlots));
841
- return (h(Host, { key: 'f16327d6866ffee76e1618fcd3281590ca0fd56d', onClick: this.onClick, class: createColorClasses(this.color, {
1062
+ const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || hasFocus || isExpanded));
1063
+ return (h(Host, { key: '5d1e5bf46d0f204efdcb55cc42cfde52e6db304b', onClick: this.onClick, class: createColorClasses(this.color, {
842
1064
  [mode]: true,
843
1065
  'in-item': inItem,
844
1066
  'in-item-color': hostContext('ion-item.ion-color', el),
@@ -856,7 +1078,7 @@ export class Select {
856
1078
  [`select-justify-${justify}`]: justifyEnabled,
857
1079
  [`select-shape-${shape}`]: shape !== undefined,
858
1080
  [`select-label-placement-${labelPlacement}`]: true,
859
- }) }, h("label", { key: 'db13f76b384a7a7461c1ad752108eadf9c0213be', class: "select-wrapper", id: "select-label", onClick: this.onLabelClick, part: "wrapper" }, this.renderLabelContainer(), h("div", { key: '2fb0e57bd596c0f525be79293b7da4aca55a9385', class: "select-wrapper-inner", part: "inner" }, h("slot", { key: 'cd694c36242789a89461ed3412af9891ad68411b', name: "start" }), h("div", { key: 'fdf62911be54f4ab29eb3c2eb153f082e76a8f49', class: "native-wrapper", ref: (el) => (this.nativeWrapperEl = el), part: "container" }, this.renderSelectText(), this.renderListbox()), h("slot", { key: 'a32f5c4b101d4d6ad45870f4c4446960009377f5', name: "end" }), !hasFloatingOrStackedLabel && this.renderSelectIcon()), hasFloatingOrStackedLabel && this.renderSelectIcon(), shouldRenderHighlight && h("div", { key: '61f792024a5f221ef4f28a3c249bd3a0de5edeab', class: "select-highlight" })), this.renderBottomContent()));
1081
+ }) }, h("label", { key: '15fd1f8e06510ae8472c621cf8cf90e51172e0be', class: "select-wrapper", id: "select-label", onClick: this.onLabelClick, part: "wrapper" }, hasOutlineFill && this.renderOutlineContainer(), h("div", { key: '7964e3d9351671899793b117896acdda25ec24c4', class: "select-start", part: "start", ref: (el) => (this.startContainerEl = el) }, h("slot", { key: 'aa309ef155c4025acfd7ed5739b5221c85097b36', name: "start" })), h("div", { key: '23d5a9dfea64a9d81b0b36d9426b15bed98901b9', class: "select-control", part: "control" }, this.renderLabel(), h("div", { key: '810da9fbfa8771e09b5fb768d64e5f04858b5833', class: "native-wrapper", ref: (el) => (this.nativeWrapperEl = el), part: "container" }, this.renderSelectText(), this.renderListbox(), !hasFloatingOrStackedLabel && this.renderSelectIcon())), h("div", { key: 'bf1c04704326ecfa14cf2e49bb76d3fb45beb08d', class: "select-end", part: "end" }, hasFloatingOrStackedLabel && this.renderSelectIcon(), h("slot", { key: '76a8bcaeefdcaa908aebd820d93171b08165cee3', name: "end" })), shouldRenderHighlight && h("div", { key: '55a9c417a82323a44e16328fd62a634d9d7c558b', class: "select-highlight" })), this.renderBottomContent()));
860
1082
  }
861
1083
  static get is() { return "ion-select"; }
862
1084
  static get encapsulation() { return "shadow"; }
@@ -1516,25 +1738,219 @@ const parseValue = (value) => {
1516
1738
  }
1517
1739
  return value.toString();
1518
1740
  };
1519
- const generateText = (opts, value, compareWith) => {
1741
+ const generateText = (opts, value, compareWith, useHTML = false) => {
1520
1742
  if (value === undefined) {
1521
1743
  return '';
1522
1744
  }
1523
1745
  if (Array.isArray(value)) {
1524
1746
  return value
1525
- .map((v) => textForValue(opts, v, compareWith))
1747
+ .map((v) => textForValue(opts, v, compareWith, useHTML))
1526
1748
  .filter((opt) => opt !== null)
1527
1749
  .join(', ');
1528
1750
  }
1529
1751
  else {
1530
- return textForValue(opts, value, compareWith) || '';
1752
+ return textForValue(opts, value, compareWith, useHTML) || '';
1531
1753
  }
1532
1754
  };
1533
- const textForValue = (opts, value, compareWith) => {
1755
+ /**
1756
+ * Returns the display text for a given value from the list of options.
1757
+ * When `useHTML` is true, returns sanitized HTML for the select text.
1758
+ * When `useHTML` is false, returns plain text for aria-label and other
1759
+ * text-only contexts.
1760
+ *
1761
+ * @param opts - The list of ion-select-option elements.
1762
+ * @param value - The value to find the matching option for.
1763
+ * @param compareWith - Custom comparison function or property name.
1764
+ * @param useHTML - If true, returns HTML string. If false, returns plain text.
1765
+ */
1766
+ const textForValue = (opts, value, compareWith, useHTML = false) => {
1534
1767
  const selectOpt = opts.find((opt) => {
1535
1768
  return compareOptions(value, getOptionValue(opt), compareWith);
1536
1769
  });
1537
- return selectOpt ? selectOpt.textContent : null;
1770
+ const customHTMLEnabled = config.get('innerHTMLTemplatesEnabled', ENABLE_HTML_CONTENT_DEFAULT);
1771
+ if (!selectOpt) {
1772
+ return null;
1773
+ }
1774
+ // Return sanitized HTML for the select text
1775
+ if (customHTMLEnabled && useHTML) {
1776
+ return getOptionContent(selectOpt, undefined, true);
1777
+ }
1778
+ /**
1779
+ * When custom HTML is enabled, extract only the default slot content.
1780
+ * This ensures aria-label and other text-only contexts read only
1781
+ * the relevant option text.
1782
+ */
1783
+ if (customHTMLEnabled) {
1784
+ const content = getOptionContent(selectOpt);
1785
+ if (typeof content === 'string') {
1786
+ return content;
1787
+ }
1788
+ /**
1789
+ * Elements were found in the default slot, extract and concatenate
1790
+ * their text content while trimming whitespace.
1791
+ */
1792
+ if (content) {
1793
+ const texts = Array.from(content.childNodes)
1794
+ .map((n) => n.textContent?.trim())
1795
+ .filter((t) => t);
1796
+ return texts.join(' ') || null;
1797
+ }
1798
+ // Empty option
1799
+ return null;
1800
+ }
1801
+ return getDefaultSlotPlainText(selectOpt);
1802
+ };
1803
+ /**
1804
+ * Trims whitespace from all text nodes within a DOM tree.
1805
+ * This prevents invisible layout shifts and unwanted gaps between
1806
+ * elements when HTML content is injected via innerHTML or cloneNode,
1807
+ * as browsers preserve whitespace (tabs, newlines, spaces) from
1808
+ * the original source markup.
1809
+ *
1810
+ * @param node The root node to start trimming text nodes from.
1811
+ */
1812
+ const trimTextNodes = (node) => {
1813
+ node.childNodes.forEach((child) => {
1814
+ if (child.nodeType === Node.TEXT_NODE) {
1815
+ child.textContent = child.textContent?.trim() || '';
1816
+ }
1817
+ else if (child.nodeType === Node.ELEMENT_NODE) {
1818
+ trimTextNodes(child);
1819
+ }
1820
+ });
1821
+ };
1822
+ /**
1823
+ * Extracts and clones content from an `ion-select-option` element
1824
+ * for rendering within overlay interfaces or the select text when `customHTMLEnabled` is `true`.
1825
+ *
1826
+ * @param option - The `ion-select-option` element to extract content from.
1827
+ * @param slotName - Optional slot name to extract. If omitted, extracts the default slot content.
1828
+ * @param useHTML - If `true`, the returned string will include any custom HTML content. If `false`, the returned string will be plain text without any HTML.
1829
+ * @returns When `useHTML` is `true`, a sanitized HTML string. When `false`, a
1830
+ * div element containing cloned child nodes. Returns `null` if no matching
1831
+ * content is found.
1832
+ */
1833
+ const getOptionContent = (option, slotName, useHTML = false) => {
1834
+ let nodes;
1835
+ if (slotName) {
1836
+ // Named slot: get elements with matching slot attribute
1837
+ nodes = Array.from(option.children).filter((el) => el.getAttribute('slot') === slotName);
1838
+ }
1839
+ else {
1840
+ // Default slot: get nodes without a slot attribute
1841
+ const defaultSlot = getOptionDefaultSlot(option) || [];
1842
+ nodes = defaultSlot.filter((node) => {
1843
+ /**
1844
+ * Exclude whitespace-only text nodes (newline noise between
1845
+ * markup elements). Element nodes are always kept, even when
1846
+ * their textContent is empty (e.g. <svg>, <img>).
1847
+ */
1848
+ if (node.nodeType === Node.TEXT_NODE) {
1849
+ return node.textContent?.trim().length !== 0;
1850
+ }
1851
+ return true;
1852
+ });
1853
+ }
1854
+ if (nodes.length === 0) {
1855
+ return null;
1856
+ }
1857
+ // Return plain text if no elements are found
1858
+ if (!slotName && nodes.every((n) => n.nodeType === Node.TEXT_NODE)) {
1859
+ return nodes.map((n) => n.textContent?.trim()).join(' ') || null;
1860
+ }
1861
+ /**
1862
+ * Mirror known custom-element properties (e.g. ion-icon's `icon`)
1863
+ * onto attributes before cloning. Frameworks like Vue set these as
1864
+ * DOM properties, which `cloneNode` doesn't copy, so without this
1865
+ * step the cloned overlay copy renders without the prop's value.
1866
+ */
1867
+ nodes.forEach((n) => {
1868
+ if (n.nodeType === Node.ELEMENT_NODE) {
1869
+ reflectPropertiesToAttributes(n);
1870
+ }
1871
+ });
1872
+ // Clone each node into a temporary container
1873
+ const container = document.createElement('div');
1874
+ nodes.forEach((n) => {
1875
+ const clone = n.cloneNode(true);
1876
+ if (clone.nodeType === Node.TEXT_NODE) {
1877
+ clone.textContent = clone.textContent?.trim() || '';
1878
+ }
1879
+ else {
1880
+ trimTextNodes(clone);
1881
+ }
1882
+ container.appendChild(clone);
1883
+ });
1884
+ /**
1885
+ * Sanitize the cloned DOM in place. Trusted attributes (size, color,
1886
+ * shape, etc.) are preserved; event handlers, javascript: URLs, and
1887
+ * blocked tags are stripped.
1888
+ */
1889
+ sanitizeDOMTree(container);
1890
+ if (useHTML) {
1891
+ return container.innerHTML.trim() || null;
1892
+ }
1893
+ return container;
1894
+ };
1895
+ /**
1896
+ * Returns the child nodes that belong to the default slot of an
1897
+ * option element, excluding any nodes that are assigned to named
1898
+ * slots.
1899
+ *
1900
+ * @param option - The `ion-select-option` element to extract default-slot nodes from.
1901
+ * @returns An array of default slot nodes, or `null` if none are found.
1902
+ */
1903
+ const getOptionDefaultSlot = (option) => {
1904
+ const defaultSlotNodes = Array.from(option.childNodes).filter((node) => {
1905
+ if (node.nodeType === Node.ELEMENT_NODE) {
1906
+ return !node.hasAttribute('slot');
1907
+ }
1908
+ return node.nodeType === Node.TEXT_NODE;
1909
+ });
1910
+ if (defaultSlotNodes.length === 0) {
1911
+ return null;
1912
+ }
1913
+ return defaultSlotNodes;
1914
+ };
1915
+ /**
1916
+ * Extracts plain text from only the default slot of an option,
1917
+ * excluding content assigned to named slots (start/end).
1918
+ */
1919
+ const getDefaultSlotPlainText = (option) => {
1920
+ const texts = Array.from(option.childNodes)
1921
+ .filter((node) => {
1922
+ if (node.nodeType === Node.ELEMENT_NODE) {
1923
+ return !node.hasAttribute('slot');
1924
+ }
1925
+ return node.nodeType === Node.TEXT_NODE;
1926
+ })
1927
+ .filter((node) => node.nodeType === Node.TEXT_NODE)
1928
+ .map((n) => n.textContent?.trim())
1929
+ .filter((t) => t);
1930
+ return texts.join(' ');
1931
+ };
1932
+ /**
1933
+ * Extracts the rich content from an `ion-select-option`.
1934
+ * When `customHTMLEnabled` is `false`, only the plain text from the
1935
+ * default slot is read and the start and end slots are skipped.
1936
+ *
1937
+ * @param option - The `ion-select-option` element to extract content from.
1938
+ * @param customHTMLEnabled - Whether custom HTML rendering is enabled
1939
+ * via the `innerHTMLTemplatesEnabled` config.
1940
+ */
1941
+ const extractOptionContent = (option, customHTMLEnabled) => {
1942
+ if (!customHTMLEnabled) {
1943
+ return {
1944
+ content: getDefaultSlotPlainText(option),
1945
+ startContent: undefined,
1946
+ endContent: undefined,
1947
+ };
1948
+ }
1949
+ return {
1950
+ content: getOptionContent(option),
1951
+ startContent: getOptionContent(option, 'start') ?? undefined,
1952
+ endContent: getOptionContent(option, 'end') ?? undefined,
1953
+ };
1538
1954
  };
1539
1955
  let selectIds = 0;
1540
1956
  const OPTION_CLASS = 'select-interface-option';