@ionic/core 8.7.16-dev.11769699401.1dc7caf4 → 8.7.16-dev.11770318223.1177a6ea

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 (481) hide show
  1. package/components/button.js +20 -15
  2. package/components/checkbox.js +3 -3
  3. package/components/content.js +3 -3
  4. package/components/header.js +2 -2
  5. package/components/helpers.js +18 -4
  6. package/components/ion-card-content.js +7 -8
  7. package/components/ion-card-header.js +2 -2
  8. package/components/ion-card-subtitle.js +2 -2
  9. package/components/ion-card-title.js +2 -2
  10. package/components/ion-chip.js +2 -2
  11. package/components/ion-col.js +2 -2
  12. package/components/ion-datetime-button.js +2 -2
  13. package/components/ion-datetime.js +11 -17
  14. package/components/ion-divider.js +2 -2
  15. package/components/ion-fab-button.js +2 -2
  16. package/components/ion-fab-list.js +2 -2
  17. package/components/ion-fab.js +2 -2
  18. package/components/ion-footer.js +2 -2
  19. package/components/ion-grid.js +2 -2
  20. package/components/ion-img.js +2 -2
  21. package/components/ion-infinite-scroll-content.js +2 -2
  22. package/components/ion-infinite-scroll.js +1 -1
  23. package/components/ion-input-otp.js +62 -7
  24. package/components/ion-input-password-toggle.js +3 -3
  25. package/components/ion-input.js +4 -4
  26. package/components/ion-item-divider.js +2 -2
  27. package/components/ion-item-group.js +1 -1
  28. package/components/ion-item-option.js +2 -2
  29. package/components/ion-item-options.js +1 -1
  30. package/components/ion-item-sliding.js +1 -1
  31. package/components/ion-loading.js +2 -2
  32. package/components/ion-menu-button.js +2 -2
  33. package/components/ion-menu-toggle.js +2 -2
  34. package/components/ion-menu.js +2 -2
  35. package/components/ion-nav-link.js +1 -1
  36. package/components/ion-nav.js +1 -1
  37. package/components/ion-note.js +2 -2
  38. package/components/ion-picker-legacy.js +2 -2
  39. package/components/ion-progress-bar.js +1 -1
  40. package/components/ion-range.js +3 -3
  41. package/components/ion-refresher-content.js +2 -2
  42. package/components/ion-refresher.js +1 -1
  43. package/components/ion-reorder-group.js +1 -1
  44. package/components/ion-reorder.js +2 -2
  45. package/components/ion-router-link.js +2 -2
  46. package/components/ion-router-outlet.js +1 -1
  47. package/components/ion-row.js +2 -2
  48. package/components/ion-searchbar.js +4 -4
  49. package/components/ion-segment-button.js +2 -2
  50. package/components/ion-segment-content.js +1 -1
  51. package/components/ion-segment-view.js +2 -2
  52. package/components/ion-segment.js +2 -2
  53. package/components/ion-select-option.js +1 -1
  54. package/components/ion-select.js +3 -3
  55. package/components/ion-skeleton-text.js +2 -2
  56. package/components/ion-split-pane.js +2 -2
  57. package/components/ion-tab-bar.js +2 -2
  58. package/components/ion-tab-button.js +2 -2
  59. package/components/ion-tab.js +2 -2
  60. package/components/ion-tabs.js +1 -1
  61. package/components/ion-text.js +2 -2
  62. package/components/ion-textarea.js +81 -14
  63. package/components/ion-thumbnail.js +2 -2
  64. package/components/ion-toast.js +2 -2
  65. package/components/ion-toggle.js +3 -3
  66. package/components/label.js +2 -2
  67. package/components/list-header.js +2 -2
  68. package/components/list.js +1 -1
  69. package/components/modal.js +4 -4
  70. package/components/overlays.js +93 -2
  71. package/components/picker-column-option.js +2 -2
  72. package/components/picker-column.js +3 -3
  73. package/components/picker-column2.js +2 -2
  74. package/components/picker.js +2 -2
  75. package/components/popover.js +2 -2
  76. package/components/radio-group.js +2 -2
  77. package/components/radio.js +3 -3
  78. package/components/ripple-effect.js +1 -1
  79. package/components/select-modal.js +1 -1
  80. package/components/select-popover.js +2 -2
  81. package/components/spinner.js +1 -1
  82. package/components/theme.js +25 -1
  83. package/components/title.js +2 -2
  84. package/components/toolbar.js +2 -2
  85. package/components/validity.js +32 -1
  86. package/css/core.css +1 -1
  87. package/css/core.css.map +1 -1
  88. package/css/ionic/bundle.ionic.css +1 -1
  89. package/css/ionic/bundle.ionic.css.map +1 -1
  90. package/css/ionic/core.ionic.css +1 -1
  91. package/css/ionic/core.ionic.css.map +1 -1
  92. package/css/ionic.bundle.css +1 -1
  93. package/css/ionic.bundle.css.map +1 -1
  94. package/dist/cjs/{animation-CD5nuON9.js → animation-C04i0Aq2.js} +2 -2
  95. package/dist/cjs/{app-globals-CoW5jvJu.js → app-globals-BP1XPbBb.js} +1 -1
  96. package/dist/cjs/{button-active-Dxyabn6T.js → button-active-B9D1nnqS.js} +2 -2
  97. package/dist/cjs/{capacitor-C8raJ_tU.js → capacitor-CbwHRb4L.js} +1 -1
  98. package/dist/cjs/{config-C5fsO43a.js → config-CPCkFfH2.js} +1 -1
  99. package/dist/cjs/{data-MoL8Ckx5.js → data-BpYscHnl.js} +1 -1
  100. package/dist/cjs/{framework-delegate-Bwdk9vFS.js → framework-delegate-C7fZ8bup.js} +2 -2
  101. package/dist/cjs/{haptic-BU6_qLwg.js → haptic-CYmISoOJ.js} +1 -1
  102. package/dist/cjs/{helpers-DnouLczu.js → helpers-DF1tCuxf.js} +19 -5
  103. package/dist/cjs/{index-C4_FN9N0.js → index-B2l1iL59.js} +4 -4
  104. package/dist/cjs/{index-JtyffOXl.js → index-BVcv37_B.js} +4 -4
  105. package/dist/cjs/{index-CADY2xEW.js → index-BioRZa_4.js} +3 -3
  106. package/dist/cjs/{index-DUoP_H1L.js → index-C2sRwpb7.js} +2 -2
  107. package/dist/cjs/{index-D6Wc6v08.js → index-DjlJwy91.js} +41 -4
  108. package/dist/cjs/index.cjs.js +12 -12
  109. package/dist/cjs/{input-shims-C-YCyXjg.js → input-shims-BYRSBwuG.js} +6 -6
  110. package/dist/cjs/{input.utils-C3-BwdV0.js → input.utils-BBh_FWGy.js} +3 -3
  111. package/dist/cjs/ion-accordion_2.cjs.entry.js +4 -4
  112. package/dist/cjs/ion-action-sheet.cjs.entry.js +10 -10
  113. package/dist/cjs/ion-alert.cjs.entry.js +11 -11
  114. package/dist/cjs/ion-app_8.cjs.entry.js +23 -23
  115. package/dist/cjs/ion-avatar_3.cjs.entry.js +5 -5
  116. package/dist/cjs/ion-back-button.cjs.entry.js +4 -4
  117. package/dist/cjs/ion-backdrop.cjs.entry.js +2 -2
  118. package/dist/cjs/ion-breadcrumb_2.cjs.entry.js +4 -4
  119. package/dist/cjs/ion-button_2.cjs.entry.js +23 -18
  120. package/dist/cjs/ion-card_5.cjs.entry.js +15 -17
  121. package/dist/cjs/ion-checkbox.cjs.entry.js +8 -8
  122. package/dist/cjs/ion-chip.cjs.entry.js +5 -5
  123. package/dist/cjs/ion-col_3.cjs.entry.js +8 -8
  124. package/dist/cjs/ion-datetime-button.cjs.entry.js +7 -7
  125. package/dist/cjs/ion-datetime_3.cjs.entry.js +21 -21
  126. package/dist/cjs/ion-divider.cjs.entry.js +4 -4
  127. package/dist/cjs/ion-fab_3.cjs.entry.js +10 -10
  128. package/dist/cjs/ion-img.cjs.entry.js +5 -5
  129. package/dist/cjs/ion-infinite-scroll_2.cjs.entry.js +8 -8
  130. package/dist/cjs/ion-input-otp.cjs.entry.js +69 -10
  131. package/dist/cjs/ion-input-password-toggle.cjs.entry.js +6 -6
  132. package/dist/cjs/ion-input.cjs.entry.js +11 -11
  133. package/dist/cjs/ion-item-option_3.cjs.entry.js +9 -9
  134. package/dist/cjs/ion-item_8.cjs.entry.js +16 -16
  135. package/dist/cjs/ion-loading.cjs.entry.js +10 -10
  136. package/dist/cjs/ion-menu_3.cjs.entry.js +14 -14
  137. package/dist/cjs/ion-modal.cjs.entry.js +16 -16
  138. package/dist/cjs/ion-nav_2.cjs.entry.js +8 -8
  139. package/dist/cjs/ion-picker-column-option.cjs.entry.js +6 -6
  140. package/dist/cjs/ion-picker-column.cjs.entry.js +9 -9
  141. package/dist/cjs/ion-picker.cjs.entry.js +4 -4
  142. package/dist/cjs/ion-popover.cjs.entry.js +10 -10
  143. package/dist/cjs/ion-progress-bar.cjs.entry.js +5 -5
  144. package/dist/cjs/ion-radio_2.cjs.entry.js +10 -10
  145. package/dist/cjs/ion-range.cjs.entry.js +8 -8
  146. package/dist/cjs/ion-refresher_2.cjs.entry.js +11 -11
  147. package/dist/cjs/ion-reorder_2.cjs.entry.js +9 -9
  148. package/dist/cjs/ion-ripple-effect.cjs.entry.js +3 -3
  149. package/dist/cjs/ion-route_4.cjs.entry.js +6 -6
  150. package/dist/cjs/ion-searchbar.cjs.entry.js +8 -8
  151. package/dist/cjs/ion-segment-content.cjs.entry.js +2 -2
  152. package/dist/cjs/ion-segment-view.cjs.entry.js +3 -3
  153. package/dist/cjs/ion-segment_2.cjs.entry.js +8 -8
  154. package/dist/cjs/ion-select-modal.cjs.entry.js +7 -7
  155. package/dist/cjs/ion-select_3.cjs.entry.js +14 -14
  156. package/dist/cjs/ion-spinner.cjs.entry.js +4 -4
  157. package/dist/cjs/ion-split-pane.cjs.entry.js +4 -4
  158. package/dist/cjs/ion-tab-bar_2.cjs.entry.js +11 -11
  159. package/dist/cjs/ion-tab_2.cjs.entry.js +6 -6
  160. package/dist/cjs/ion-text.cjs.entry.js +5 -5
  161. package/dist/cjs/ion-textarea.cjs.entry.js +88 -18
  162. package/dist/cjs/ion-toast.cjs.entry.js +10 -10
  163. package/dist/cjs/ion-toggle.cjs.entry.js +10 -10
  164. package/dist/cjs/{ionic-global-DpRwOXLK.js → ionic-global-Dq_E1GCa.js} +5 -5
  165. package/dist/cjs/ionic.cjs.js +4 -4
  166. package/dist/cjs/{ios.transition-Dt4GT8w5.js → ios.transition-DRha8gOi.js} +5 -5
  167. package/dist/cjs/{keyboard-B8HJHbg3.js → keyboard-DYFGJjuN.js} +4 -4
  168. package/dist/cjs/{keyboard-controller-O8n0dTQz.js → keyboard-controller-DNlzZiH-.js} +3 -3
  169. package/dist/cjs/{keyboard-BlrG3xPK.js → keyboard-sMvh7TE6.js} +1 -1
  170. package/dist/cjs/loader.cjs.js +4 -4
  171. package/dist/cjs/{md.transition-BolcQzNP.js → md.transition-Dh46qaSH.js} +5 -5
  172. package/dist/cjs/{notch-controller-BE80VRju.js → notch-controller-qvgjFR8h.js} +2 -2
  173. package/dist/cjs/{overlays-CRSQCKrz.js → overlays-CA-nLfRi.js} +97 -6
  174. package/dist/cjs/{status-tap-e-hyosXV.js → status-tap-BLw3gi_z.js} +3 -3
  175. package/dist/cjs/{swipe-back-CR060nOX.js → swipe-back-BD2lWufH.js} +2 -2
  176. package/dist/cjs/{theme-CeDs6Hcv.js → theme-IlOsGAz7.js} +25 -1
  177. package/dist/cjs/validity-QmuwEptc.js +51 -0
  178. package/dist/collection/components/button/button.ionic.css +10 -0
  179. package/dist/collection/components/button/button.ios.css +19 -0
  180. package/dist/collection/components/button/button.js +17 -12
  181. package/dist/collection/components/button/button.md.css +24 -0
  182. package/dist/collection/components/card-content/card-content.ionic.css +4 -7
  183. package/dist/collection/components/card-content/card-content.ios.css +5 -35
  184. package/dist/collection/components/card-content/card-content.js +3 -4
  185. package/dist/collection/components/card-content/card-content.md.css +5 -35
  186. package/dist/collection/components/card-header/card-header.js +2 -2
  187. package/dist/collection/components/card-subtitle/card-subtitle.js +2 -2
  188. package/dist/collection/components/card-title/card-title.js +2 -2
  189. package/dist/collection/components/checkbox/checkbox.js +3 -3
  190. package/dist/collection/components/chip/chip.js +2 -2
  191. package/dist/collection/components/col/col.js +2 -2
  192. package/dist/collection/components/content/content.js +3 -3
  193. package/dist/collection/components/datetime/datetime.ionic.css +5 -13
  194. package/dist/collection/components/datetime/datetime.ios.css +47 -12
  195. package/dist/collection/components/datetime/datetime.js +4 -4
  196. package/dist/collection/components/datetime/datetime.md.css +37 -2
  197. package/dist/collection/components/datetime-button/datetime-button.js +2 -2
  198. package/dist/collection/components/divider/divider.js +2 -2
  199. package/dist/collection/components/fab/fab.js +2 -2
  200. package/dist/collection/components/fab-button/fab-button.js +2 -2
  201. package/dist/collection/components/fab-list/fab-list.js +2 -2
  202. package/dist/collection/components/footer/footer.js +2 -2
  203. package/dist/collection/components/grid/grid.js +2 -2
  204. package/dist/collection/components/header/header.js +2 -2
  205. package/dist/collection/components/img/img.js +2 -2
  206. package/dist/collection/components/infinite-scroll/infinite-scroll.js +1 -1
  207. package/dist/collection/components/infinite-scroll-content/infinite-scroll-content.js +2 -2
  208. package/dist/collection/components/input/input.js +4 -4
  209. package/dist/collection/components/input-otp/input-otp.ionic.css +2 -0
  210. package/dist/collection/components/input-otp/input-otp.ios.css +3 -0
  211. package/dist/collection/components/input-otp/input-otp.js +69 -4
  212. package/dist/collection/components/input-otp/input-otp.md.css +3 -0
  213. package/dist/collection/components/input-password-toggle/input-password-toggle.js +3 -3
  214. package/dist/collection/components/item-divider/item-divider.js +2 -2
  215. package/dist/collection/components/item-group/item-group.js +1 -1
  216. package/dist/collection/components/item-option/item-option.js +2 -2
  217. package/dist/collection/components/item-options/item-options.js +1 -1
  218. package/dist/collection/components/item-sliding/item-sliding.js +1 -1
  219. package/dist/collection/components/label/label.js +2 -2
  220. package/dist/collection/components/list/list.js +1 -1
  221. package/dist/collection/components/list-header/list-header.js +2 -2
  222. package/dist/collection/components/loading/loading.js +2 -2
  223. package/dist/collection/components/menu/menu.js +2 -2
  224. package/dist/collection/components/menu-button/menu-button.js +2 -2
  225. package/dist/collection/components/menu-toggle/menu-toggle.js +2 -2
  226. package/dist/collection/components/modal/modal.js +4 -4
  227. package/dist/collection/components/nav/nav.js +1 -1
  228. package/dist/collection/components/nav-link/nav-link.js +1 -1
  229. package/dist/collection/components/note/note.js +2 -2
  230. package/dist/collection/components/picker/picker.js +2 -2
  231. package/dist/collection/components/picker-column/picker-column.js +3 -3
  232. package/dist/collection/components/picker-column-option/picker-column-option.js +2 -2
  233. package/dist/collection/components/picker-legacy/picker.js +2 -2
  234. package/dist/collection/components/picker-legacy-column/picker-column.js +2 -2
  235. package/dist/collection/components/popover/popover.js +2 -2
  236. package/dist/collection/components/progress-bar/progress-bar.js +1 -1
  237. package/dist/collection/components/radio/radio.js +3 -3
  238. package/dist/collection/components/radio-group/radio-group.js +2 -2
  239. package/dist/collection/components/range/range.js +3 -3
  240. package/dist/collection/components/refresher/refresher.js +1 -1
  241. package/dist/collection/components/refresher-content/refresher-content.js +2 -2
  242. package/dist/collection/components/reorder/reorder.js +2 -2
  243. package/dist/collection/components/reorder-group/reorder-group.js +1 -1
  244. package/dist/collection/components/ripple-effect/ripple-effect.js +1 -1
  245. package/dist/collection/components/router-link/router-link.js +2 -2
  246. package/dist/collection/components/router-outlet/router-outlet.js +1 -1
  247. package/dist/collection/components/row/row.js +2 -2
  248. package/dist/collection/components/searchbar/searchbar.js +4 -4
  249. package/dist/collection/components/segment/segment.js +2 -2
  250. package/dist/collection/components/segment-button/segment-button.js +2 -2
  251. package/dist/collection/components/segment-content/segment-content.js +1 -1
  252. package/dist/collection/components/segment-view/segment-view.js +2 -2
  253. package/dist/collection/components/select/select.js +3 -3
  254. package/dist/collection/components/select-modal/select-modal.js +1 -1
  255. package/dist/collection/components/select-option/select-option.js +1 -1
  256. package/dist/collection/components/select-popover/select-popover.js +2 -2
  257. package/dist/collection/components/skeleton-text/skeleton-text.js +2 -2
  258. package/dist/collection/components/spinner/spinner.js +1 -1
  259. package/dist/collection/components/split-pane/split-pane.js +2 -2
  260. package/dist/collection/components/tab/tab.js +2 -2
  261. package/dist/collection/components/tab-bar/tab-bar.js +2 -2
  262. package/dist/collection/components/tab-button/tab-button.js +2 -2
  263. package/dist/collection/components/tabs/tabs.js +1 -1
  264. package/dist/collection/components/text/text.js +2 -2
  265. package/dist/collection/components/textarea/textarea.ionic.css +13 -20
  266. package/dist/collection/components/textarea/textarea.ios.css +8 -14
  267. package/dist/collection/components/textarea/textarea.js +89 -11
  268. package/dist/collection/components/textarea/textarea.md.css +9 -14
  269. package/dist/collection/components/thumbnail/thumbnail.js +2 -2
  270. package/dist/collection/components/title/title.js +2 -2
  271. package/dist/collection/components/toast/toast.js +2 -2
  272. package/dist/collection/components/toggle/toggle.js +3 -3
  273. package/dist/collection/components/toolbar/toolbar.js +2 -2
  274. package/dist/collection/utils/focus-trap.js +13 -2
  275. package/dist/collection/utils/forms/validity.js +31 -0
  276. package/dist/collection/utils/helpers.js +18 -4
  277. package/dist/collection/utils/overlays.js +80 -0
  278. package/dist/collection/utils/theme.js +25 -1
  279. package/dist/docs.json +178 -15
  280. package/dist/esm/{animation-BNuoDl-O.js → animation-C5cgFymd.js} +2 -2
  281. package/dist/esm/{app-globals-tX0s9Zd7.js → app-globals-BQa4bHAm.js} +1 -1
  282. package/dist/esm/{button-active-BF6GZ_yH.js → button-active-DpavRUgB.js} +2 -2
  283. package/dist/esm/{capacitor-pzVAlnC0.js → capacitor-Bc47Xxvc.js} +1 -1
  284. package/dist/esm/{config-mCdtaoPe.js → config-DK9FWNvn.js} +1 -1
  285. package/dist/esm/{data-DFCY8gnk.js → data-B5lRlGxI.js} +1 -1
  286. package/dist/esm/{framework-delegate-D2mUP0WI.js → framework-delegate-Dx6tn-_w.js} +2 -2
  287. package/dist/esm/{haptic-bBvyATla.js → haptic-Dti4RWuD.js} +1 -1
  288. package/dist/esm/{helpers-Bsml3FcE.js → helpers-6l6yFg3S.js} +19 -5
  289. package/dist/esm/{index-Bnw-zNoN.js → index-B6MWWbnL.js} +3 -3
  290. package/dist/esm/{index-BpFi2B8W.js → index-CXCvNx5X.js} +2 -2
  291. package/dist/esm/{index-BQI9hSZP.js → index-DO9elf_6.js} +4 -4
  292. package/dist/esm/{index-C8IsBmNU.js → index-gD7P82jx.js} +41 -4
  293. package/dist/esm/{index-M3l-IyxQ.js → index-urxfV0GK.js} +4 -4
  294. package/dist/esm/index.js +12 -12
  295. package/dist/esm/{input-shims-ACbgRt10.js → input-shims-CK_oprMl.js} +6 -6
  296. package/dist/esm/{input.utils-loPnHH5H.js → input.utils-C3tJs_iL.js} +3 -3
  297. package/dist/esm/ion-accordion_2.entry.js +4 -4
  298. package/dist/esm/ion-action-sheet.entry.js +10 -10
  299. package/dist/esm/ion-alert.entry.js +11 -11
  300. package/dist/esm/ion-app_8.entry.js +23 -23
  301. package/dist/esm/ion-avatar_3.entry.js +5 -5
  302. package/dist/esm/ion-back-button.entry.js +4 -4
  303. package/dist/esm/ion-backdrop.entry.js +2 -2
  304. package/dist/esm/ion-breadcrumb_2.entry.js +4 -4
  305. package/dist/esm/ion-button_2.entry.js +23 -18
  306. package/dist/esm/ion-card_5.entry.js +15 -17
  307. package/dist/esm/ion-checkbox.entry.js +8 -8
  308. package/dist/esm/ion-chip.entry.js +5 -5
  309. package/dist/esm/ion-col_3.entry.js +8 -8
  310. package/dist/esm/ion-datetime-button.entry.js +7 -7
  311. package/dist/esm/ion-datetime_3.entry.js +21 -21
  312. package/dist/esm/ion-divider.entry.js +4 -4
  313. package/dist/esm/ion-fab_3.entry.js +10 -10
  314. package/dist/esm/ion-img.entry.js +5 -5
  315. package/dist/esm/ion-infinite-scroll_2.entry.js +8 -8
  316. package/dist/esm/ion-input-otp.entry.js +69 -10
  317. package/dist/esm/ion-input-password-toggle.entry.js +6 -6
  318. package/dist/esm/ion-input.entry.js +11 -11
  319. package/dist/esm/ion-item-option_3.entry.js +9 -9
  320. package/dist/esm/ion-item_8.entry.js +16 -16
  321. package/dist/esm/ion-loading.entry.js +10 -10
  322. package/dist/esm/ion-menu_3.entry.js +14 -14
  323. package/dist/esm/ion-modal.entry.js +16 -16
  324. package/dist/esm/ion-nav_2.entry.js +8 -8
  325. package/dist/esm/ion-picker-column-option.entry.js +6 -6
  326. package/dist/esm/ion-picker-column.entry.js +9 -9
  327. package/dist/esm/ion-picker.entry.js +4 -4
  328. package/dist/esm/ion-popover.entry.js +10 -10
  329. package/dist/esm/ion-progress-bar.entry.js +5 -5
  330. package/dist/esm/ion-radio_2.entry.js +10 -10
  331. package/dist/esm/ion-range.entry.js +8 -8
  332. package/dist/esm/ion-refresher_2.entry.js +11 -11
  333. package/dist/esm/ion-reorder_2.entry.js +9 -9
  334. package/dist/esm/ion-ripple-effect.entry.js +3 -3
  335. package/dist/esm/ion-route_4.entry.js +6 -6
  336. package/dist/esm/ion-searchbar.entry.js +8 -8
  337. package/dist/esm/ion-segment-content.entry.js +2 -2
  338. package/dist/esm/ion-segment-view.entry.js +3 -3
  339. package/dist/esm/ion-segment_2.entry.js +8 -8
  340. package/dist/esm/ion-select-modal.entry.js +7 -7
  341. package/dist/esm/ion-select_3.entry.js +14 -14
  342. package/dist/esm/ion-spinner.entry.js +4 -4
  343. package/dist/esm/ion-split-pane.entry.js +4 -4
  344. package/dist/esm/ion-tab-bar_2.entry.js +11 -11
  345. package/dist/esm/ion-tab_2.entry.js +6 -6
  346. package/dist/esm/ion-text.entry.js +5 -5
  347. package/dist/esm/ion-textarea.entry.js +88 -18
  348. package/dist/esm/ion-toast.entry.js +10 -10
  349. package/dist/esm/ion-toggle.entry.js +10 -10
  350. package/dist/esm/{ionic-global-2lDD9k7y.js → ionic-global-KnoA5TnE.js} +5 -5
  351. package/dist/esm/ionic.js +5 -5
  352. package/dist/esm/{ios.transition-uJxJFbq8.js → ios.transition-D-ZEPllL.js} +5 -5
  353. package/dist/esm/{keyboard-CU1vRv-b.js → keyboard-C7jpSDLg.js} +1 -1
  354. package/dist/esm/{keyboard-B-HHSSYU.js → keyboard-CrGPuspU.js} +4 -4
  355. package/dist/esm/{keyboard-controller-Dplyc4OV.js → keyboard-controller-CFeM2qrY.js} +3 -3
  356. package/dist/esm/loader.js +5 -5
  357. package/dist/esm/{md.transition-Dp4NTeSh.js → md.transition-DiPaaGY2.js} +5 -5
  358. package/dist/esm/{notch-controller-BvFDmO69.js → notch-controller-CEiB8plC.js} +2 -2
  359. package/dist/esm/{overlays-B037a9Tz.js → overlays-BMHHx7Tm.js} +97 -6
  360. package/dist/esm/{status-tap-DXVlluKS.js → status-tap-BAJGCN-1.js} +3 -3
  361. package/dist/esm/{swipe-back-DNhAt9fY.js → swipe-back-bZ7qcCmT.js} +2 -2
  362. package/dist/esm/{theme-DiVJyqlX.js → theme-DaJxRxSQ.js} +25 -1
  363. package/dist/esm/validity-BjW8SOqw.js +48 -0
  364. package/dist/html.html-data.json +28 -1
  365. package/dist/ionic/index.esm.js +1 -1
  366. package/dist/ionic/ionic.esm.js +1 -1
  367. package/dist/ionic/{p-5daa0980.entry.js → p-01dec443.entry.js} +1 -1
  368. package/dist/ionic/{p-04b1d37a.entry.js → p-01e2ad58.entry.js} +1 -1
  369. package/dist/ionic/{p-112e1ca9.entry.js → p-04c2c873.entry.js} +1 -1
  370. package/dist/ionic/{p-28a9d991.entry.js → p-09aab7d0.entry.js} +1 -1
  371. package/dist/ionic/{p-be82dc77.entry.js → p-0b51f337.entry.js} +1 -1
  372. package/dist/ionic/{p-616dd053.entry.js → p-131e3b2d.entry.js} +1 -1
  373. package/dist/ionic/{p-0f124806.entry.js → p-1454c314.entry.js} +1 -1
  374. package/dist/ionic/p-14c73725.entry.js +4 -0
  375. package/dist/ionic/p-14d44c66.entry.js +4 -0
  376. package/dist/ionic/{p-a35678f4.entry.js → p-1af56d46.entry.js} +1 -1
  377. package/dist/ionic/{p-0744265c.entry.js → p-1c00e5cc.entry.js} +1 -1
  378. package/dist/ionic/{p-0ac7c560.entry.js → p-25db2a16.entry.js} +1 -1
  379. package/dist/ionic/{p-60549f06.entry.js → p-2ef8db38.entry.js} +1 -1
  380. package/dist/ionic/{p-0607ce8e.entry.js → p-31706aa0.entry.js} +1 -1
  381. package/dist/ionic/{p-19b2060d.entry.js → p-39f88b4f.entry.js} +1 -1
  382. package/dist/ionic/p-3b163efb.entry.js +4 -0
  383. package/dist/ionic/{p-ecba552f.entry.js → p-3d69c783.entry.js} +1 -1
  384. package/dist/ionic/{p-e1d84521.entry.js → p-3d7263e2.entry.js} +1 -1
  385. package/dist/ionic/p-3f93e610.entry.js +4 -0
  386. package/dist/ionic/{p-Cq83JWMg.js → p-44OfGWEp.js} +1 -1
  387. package/dist/ionic/{p-5543b7b8.entry.js → p-45ffc1cb.entry.js} +1 -1
  388. package/dist/ionic/{p-a89211bd.entry.js → p-4d7a2141.entry.js} +1 -1
  389. package/dist/ionic/{p-f667945d.entry.js → p-51ddc430.entry.js} +1 -1
  390. package/dist/ionic/{p-d9c9592a.entry.js → p-69bef533.entry.js} +1 -1
  391. package/dist/ionic/{p-dacd8666.entry.js → p-717fa143.entry.js} +1 -1
  392. package/dist/ionic/{p-742fed9f.entry.js → p-7482c8b3.entry.js} +1 -1
  393. package/dist/ionic/{p-bd295ca7.entry.js → p-74cab2da.entry.js} +1 -1
  394. package/dist/ionic/p-788de6f7.entry.js +4 -0
  395. package/dist/ionic/{p-01577340.entry.js → p-7ab2b10c.entry.js} +1 -1
  396. package/dist/ionic/{p-ecf8e713.entry.js → p-7dc9aa9a.entry.js} +1 -1
  397. package/dist/ionic/{p-27dbb44c.entry.js → p-7f6069f4.entry.js} +1 -1
  398. package/dist/ionic/{p-472b2ca3.entry.js → p-8093e290.entry.js} +1 -1
  399. package/dist/ionic/{p-59a79bd9.entry.js → p-82ca1cae.entry.js} +1 -1
  400. package/dist/ionic/{p-5f9d9c14.entry.js → p-83c3c072.entry.js} +1 -1
  401. package/dist/ionic/p-8ddbeb52.entry.js +4 -0
  402. package/dist/ionic/{p-af1f624e.entry.js → p-9e985573.entry.js} +1 -1
  403. package/dist/ionic/p-9f29b55e.entry.js +4 -0
  404. package/dist/ionic/{p-qZR4N8Lu.js → p-B0QqVGqF.js} +1 -1
  405. package/dist/ionic/p-BAmXMA83.js +4 -0
  406. package/dist/ionic/p-BIyO17h7.js +4 -0
  407. package/dist/ionic/p-BjW8SOqw.js +4 -0
  408. package/dist/ionic/{p-UafGZQ8e.js → p-Br3trE7L.js} +1 -1
  409. package/dist/ionic/{p-DeEDqH91.js → p-BunTRNUk.js} +1 -1
  410. package/dist/ionic/p-CCy93Kdo.js +4 -0
  411. package/dist/ionic/{p-HpOiAvpC.js → p-CDRncjej.js} +1 -1
  412. package/dist/ionic/{p-CtUK3cKk.js → p-CH4Ab9QE.js} +1 -1
  413. package/dist/ionic/{p-B3uz75uZ.js → p-CYW7idR0.js} +1 -1
  414. package/dist/ionic/{p-B-D7Cfki.js → p-Ccfet-fb.js} +1 -1
  415. package/dist/ionic/p-CdcKo7Br.js +4 -0
  416. package/dist/ionic/{p-COLHV2ym.js → p-CsyYiC5f.js} +1 -1
  417. package/dist/ionic/{p-DyaKZbAH.js → p-CtS5hTli.js} +1 -1
  418. package/dist/ionic/{p-DbQ5QkTP.js → p-Cv5jk_TK.js} +1 -1
  419. package/dist/ionic/{p-q1ZSn0l7.js → p-CzuA64hv.js} +1 -1
  420. package/dist/ionic/{p-D-BelbiX.js → p-DGDvjMxF.js} +1 -1
  421. package/dist/ionic/p-DKogfaNJ.js +4 -0
  422. package/dist/ionic/p-DOsU-ODO.js +4 -0
  423. package/dist/ionic/p-DPrmF8Ki.js +4 -0
  424. package/dist/ionic/p-DYzvRXm5.js +4 -0
  425. package/dist/ionic/p-DaJxRxSQ.js +4 -0
  426. package/dist/ionic/{p-CvRDI-Iz.js → p-TL0QOgYo.js} +1 -1
  427. package/dist/ionic/p-We-0jbXn.js +4 -0
  428. package/dist/ionic/{p-c082f853.entry.js → p-a0c5e546.entry.js} +1 -1
  429. package/dist/ionic/{p-0eecce18.entry.js → p-a339cde1.entry.js} +1 -1
  430. package/dist/ionic/p-a59f21b3.entry.js +4 -0
  431. package/dist/ionic/{p-d3f64c58.entry.js → p-a5f4fe92.entry.js} +1 -1
  432. package/dist/ionic/{p-826267d6.entry.js → p-aaff29dd.entry.js} +1 -1
  433. package/dist/ionic/{p-0c41c8a8.entry.js → p-b4da10d5.entry.js} +1 -1
  434. package/dist/ionic/{p-8f541b05.entry.js → p-bb04a3d7.entry.js} +1 -1
  435. package/dist/ionic/{p-a6a37a34.entry.js → p-bc19095e.entry.js} +1 -1
  436. package/dist/ionic/{p-8ee09d4e.entry.js → p-bd0057bd.entry.js} +1 -1
  437. package/dist/ionic/{p-da49c0fe.entry.js → p-bf763ab7.entry.js} +1 -1
  438. package/dist/ionic/{p-cdbfbff6.entry.js → p-c66416de.entry.js} +1 -1
  439. package/dist/ionic/{p-b475ec18.entry.js → p-d103fef9.entry.js} +1 -1
  440. package/dist/ionic/{p-68c064ce.entry.js → p-d9c0d206.entry.js} +1 -1
  441. package/dist/ionic/{p-412d5d9e.entry.js → p-e278c474.entry.js} +1 -1
  442. package/dist/ionic/{p-6bb99f41.entry.js → p-e8344f8f.entry.js} +1 -1
  443. package/dist/ionic/{p-04e0ff62.entry.js → p-ec510664.entry.js} +1 -1
  444. package/dist/ionic/p-eyZt9Ndv.js +4 -0
  445. package/dist/ionic/{p-8681a2a7.entry.js → p-f0894af8.entry.js} +1 -1
  446. package/dist/ionic/p-gD7P82jx.js +5 -0
  447. package/dist/ionic/p-hPTD29t1.js +4 -0
  448. package/dist/types/components/button/button.d.ts +4 -2
  449. package/dist/types/components/input-otp/input-otp.d.ts +37 -0
  450. package/dist/types/components/textarea/textarea.d.ts +36 -0
  451. package/dist/types/components.d.ts +18 -2
  452. package/dist/types/utils/focus-trap.d.ts +1 -1
  453. package/dist/types/utils/forms/validity.d.ts +7 -0
  454. package/dist/types/utils/theme.d.ts +9 -0
  455. package/hydrate/index.js +527 -210
  456. package/hydrate/index.mjs +527 -210
  457. package/package.json +1 -1
  458. package/dist/cjs/validity-BpS37YFM.js +0 -19
  459. package/dist/esm/validity-DJztqcrH.js +0 -17
  460. package/dist/ionic/p-2dc676b2.entry.js +0 -4
  461. package/dist/ionic/p-381eb2a4.entry.js +0 -4
  462. package/dist/ionic/p-57a2d30b.entry.js +0 -4
  463. package/dist/ionic/p-63a2b52a.entry.js +0 -4
  464. package/dist/ionic/p-7fe3ea65.entry.js +0 -4
  465. package/dist/ionic/p-83580e97.entry.js +0 -4
  466. package/dist/ionic/p-BiTKUjko.js +0 -4
  467. package/dist/ionic/p-ByhhQryg.js +0 -4
  468. package/dist/ionic/p-C8IsBmNU.js +0 -5
  469. package/dist/ionic/p-C8r4dtYR.js +0 -4
  470. package/dist/ionic/p-CK1xn1Nt.js +0 -4
  471. package/dist/ionic/p-C_97se21.js +0 -4
  472. package/dist/ionic/p-DHeUgOSJ.js +0 -4
  473. package/dist/ionic/p-DJztqcrH.js +0 -4
  474. package/dist/ionic/p-DM-v_NNE.js +0 -4
  475. package/dist/ionic/p-DiVJyqlX.js +0 -4
  476. package/dist/ionic/p-DoGrslUl.js +0 -4
  477. package/dist/ionic/p-Dq8ap6AD.js +0 -4
  478. package/dist/ionic/p-add1a5d8.entry.js +0 -4
  479. package/dist/ionic/p-da0a2ca6.entry.js +0 -4
  480. package/dist/ionic/p-nP9c7bo5.js +0 -4
  481. package/dist/ionic/p-of4jy1ch.js +0 -4
@@ -2,7 +2,7 @@
2
2
  * (C) Ionic http://ionicframework.com - MIT License
3
3
  */
4
4
  import { Build, Host, forceUpdate, h, writeTask, } from "@stencil/core";
5
- import { createNotchController, checkInvalidState } from "../../utils/forms/index";
5
+ import { createNotchController, checkInvalidState, reportValidityToElementInternals } from "../../utils/forms/index";
6
6
  import { inheritAriaAttributes, debounceEvent, inheritAttributes, componentOnReady } from "../../utils/helpers";
7
7
  import { createSlotMutationController } from "../../utils/slot-mutation-controller";
8
8
  import { createColorClasses, hostContext } from "../../utils/theme";
@@ -15,6 +15,16 @@ import { getCounterText } from "../input/input.utils";
15
15
  * @slot label - The label text to associate with the textarea. Use the `labelPlacement` property to control where the label is placed relative to the textarea. Use this if you need to render a label with custom HTML. (EXPERIMENTAL)
16
16
  * @slot start - Content to display at the leading edge of the textarea. (EXPERIMENTAL)
17
17
  * @slot end - Content to display at the trailing edge of the textarea. (EXPERIMENTAL)
18
+ *
19
+ * @part wrapper - The clickable label element that wraps the entire form field (label text, slots, and native textarea).
20
+ * @part container - The inner wrapper element that directly contains the native textarea element.
21
+ * @part label - The label text describing the textarea.
22
+ * @part native - The native textarea element.
23
+ * @part supporting-text - Supporting text displayed beneath the textarea label.
24
+ * @part helper-text - Supporting text displayed beneath the textarea label when the textarea is valid.
25
+ * @part error-text - Supporting text displayed beneath the textarea label when the textarea is invalid and touched.
26
+ * @part counter - The character counter displayed when the counter property is set.
27
+ * @part bottom - The container element for helper text, error text, and counter.
18
28
  */
19
29
  export class Textarea {
20
30
  constructor() {
@@ -161,6 +171,12 @@ export class Textarea {
161
171
  */
162
172
  this.ionInput = debounce === undefined ? originalIonInput !== null && originalIonInput !== void 0 ? originalIonInput : ionInput : debounceEvent(ionInput, debounce);
163
173
  }
174
+ /**
175
+ * Update element internals when disabled prop changes
176
+ */
177
+ disabledChanged() {
178
+ this.updateElementInternals();
179
+ }
164
180
  /**
165
181
  * Update the native input element when the value changes
166
182
  */
@@ -170,8 +186,22 @@ export class Textarea {
170
186
  if (nativeInput && nativeInput.value !== value) {
171
187
  nativeInput.value = value;
172
188
  }
189
+ this.updateElementInternals();
173
190
  this.runAutoGrow();
174
191
  }
192
+ /**
193
+ * Update native input and element internals when required prop changes
194
+ */
195
+ requiredChanged() {
196
+ // Explicitly update the native element's required attribute to ensure
197
+ // browser validation works correctly when required changes dynamically.
198
+ // While the template binding should handle this, we need to update it
199
+ // synchronously for the browser's validation to recognize the change.
200
+ if (this.nativeInput) {
201
+ this.nativeInput.required = this.required;
202
+ }
203
+ this.updateElementInternals();
204
+ }
175
205
  /**
176
206
  * dir is a globally enumerated attribute.
177
207
  * As a result, creating these as properties
@@ -247,7 +277,14 @@ export class Textarea {
247
277
  }
248
278
  componentDidLoad() {
249
279
  this.originalIonInput = this.ionInput;
280
+ this.updateElementInternals();
250
281
  this.runAutoGrow();
282
+ // Override focus() to delegate to the native textarea.
283
+ // This is needed for Safari and Firefox which don't properly
284
+ // delegate focus when calling focus() directly on the host.
285
+ this.el.focus = () => {
286
+ this.setFocus();
287
+ };
251
288
  }
252
289
  componentDidRender() {
253
290
  var _a;
@@ -356,12 +393,43 @@ export class Textarea {
356
393
  getValue() {
357
394
  return this.value || '';
358
395
  }
396
+ /**
397
+ * Called when the form state is restored.
398
+ * Restores the component's value.
399
+ */
400
+ formStateRestoreCallback(value) {
401
+ this.value = value;
402
+ }
403
+ /**
404
+ * Called when the form is reset.
405
+ * Resets the component's value.
406
+ */
407
+ formResetCallback() {
408
+ this.value = '';
409
+ }
410
+ /**
411
+ * Updates the form value and reports validity state to the browser via
412
+ * ElementInternals. This should be called when the component loads, when
413
+ * the required prop changes, when the disabled prop changes, and when the value
414
+ * changes to ensure the form value stays in sync and validation state is updated.
415
+ */
416
+ updateElementInternals() {
417
+ // Disabled form controls should not be included in form data
418
+ // Pass null to setFormValue when disabled to exclude it from form submission
419
+ const value = this.disabled ? null : this.getValue();
420
+ // ElementInternals may not be fully available in test environments
421
+ // so we need to check if the method exists before calling it
422
+ if (typeof this.internals.setFormValue === 'function') {
423
+ this.internals.setFormValue(value);
424
+ }
425
+ reportValidityToElementInternals(this.nativeInput, this.internals);
426
+ }
359
427
  renderLabel() {
360
428
  const { label } = this;
361
429
  return (h("div", { class: {
362
430
  'label-text-wrapper': true,
363
431
  'label-text-wrapper-hidden': !this.hasLabel,
364
- } }, label === undefined ? h("slot", { name: "label" }) : h("div", { class: "label-text" }, label)));
432
+ }, part: "label" }, label === undefined ? h("slot", { name: "label" }) : h("div", { class: "label-text" }, label)));
365
433
  }
366
434
  /**
367
435
  * Gets any content passed into the `label` slot,
@@ -430,8 +498,8 @@ export class Textarea {
430
498
  renderHintText() {
431
499
  const { helperText, errorText, helperTextId, errorTextId, isInvalid } = this;
432
500
  return [
433
- h("div", { id: helperTextId, class: "helper-text", "aria-live": "polite" }, !isInvalid ? helperText : null),
434
- h("div", { id: errorTextId, class: "error-text", role: "alert" }, isInvalid ? errorText : null),
501
+ h("div", { id: helperTextId, class: "helper-text", part: "supporting-text helper-text", "aria-live": "polite" }, !isInvalid ? helperText : null),
502
+ h("div", { id: errorTextId, class: "error-text", part: "supporting-text error-text", role: "alert" }, isInvalid ? errorText : null),
435
503
  ];
436
504
  }
437
505
  getHintTextID() {
@@ -449,7 +517,7 @@ export class Textarea {
449
517
  if (counter !== true || maxlength === undefined) {
450
518
  return;
451
519
  }
452
- return h("div", { class: "counter" }, getCounterText(value, maxlength, counterFormatter));
520
+ return (h("div", { class: "counter", part: "counter" }, getCounterText(value, maxlength, counterFormatter)));
453
521
  }
454
522
  /**
455
523
  * Responsible for rendering helper text,
@@ -467,7 +535,7 @@ export class Textarea {
467
535
  if (!hasHintText && !hasCounter) {
468
536
  return;
469
537
  }
470
- return (h("div", { class: "textarea-bottom" }, this.renderHintText(), this.renderCounter()));
538
+ return (h("div", { class: "textarea-bottom", part: "bottom" }, this.renderHintText(), this.renderCounter()));
471
539
  }
472
540
  render() {
473
541
  const { inputId, disabled, readonly, size, labelPlacement, el, hasFocus } = this;
@@ -497,7 +565,7 @@ export class Textarea {
497
565
  * TODO(FW-5592): Remove hasStartEndSlots condition
498
566
  */
499
567
  const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || hasFocus || hasStartEndSlots));
500
- return (h(Host, { key: 'f361b0d612ea373b27f5daa3b0d86f5a87e3a347', class: createColorClasses(this.color, {
568
+ return (h(Host, { key: '5be3ab7c5adf5ef61d70aff916d233239cc3034e', class: createColorClasses(this.color, {
501
569
  [theme]: true,
502
570
  'has-value': hasValue,
503
571
  'has-focus': hasFocus,
@@ -506,9 +574,10 @@ export class Textarea {
506
574
  [`textarea-shape-${shape}`]: shape !== undefined,
507
575
  [`textarea-size-${size}`]: true,
508
576
  [`textarea-label-placement-${labelPlacement}`]: true,
577
+ 'in-item': inItem,
509
578
  'textarea-disabled': disabled,
510
579
  'textarea-readonly': readonly,
511
- }) }, h("label", { key: '56f39fa4c6ed77958165084bc07addcb4f4878fa', class: "textarea-wrapper", htmlFor: inputId, onClick: this.onLabelClick }, this.renderLabelContainer(), h("div", { key: '14972dea04325a7dbdeae65fa22263b412f9f023', class: "textarea-wrapper-inner" },
580
+ }) }, h("label", { key: '7eb9826e9618606e1de74cb842c9236a2b5d0cb4', class: "textarea-wrapper", htmlFor: inputId, onClick: this.onLabelClick, part: "wrapper" }, this.renderLabelContainer(), h("div", { key: '5f0362d9f1f07f73b3d7d89d55fcb463ad0bc1da', class: "textarea-wrapper-inner" },
512
581
  /**
513
582
  * For the ionic theme, we render the outline container here
514
583
  * instead of higher up, so it can be positioned relative to
@@ -518,10 +587,12 @@ export class Textarea {
518
587
  * <label> element, ensuring that clicking the label text
519
588
  * focuses the textarea.
520
589
  */
521
- theme === 'ionic' && fill === 'outline' && h("div", { key: '42c8c5948c86e9a0342fcb2e6b8dceff320dec82', class: "textarea-outline" }), h("div", { key: '75c3c69bb990b9e85765ee3825e3a49fd3bb3d7f', class: "start-slot-wrapper" }, h("slot", { key: '3d3459222c5572277f36af98d9156d64a0646461', name: "start" })), h("div", { key: '84bd1c9cb2b018e27c30af4bdba345674f2c3f18', class: "native-wrapper", ref: (el) => (this.textareaWrapper = el) }, h("textarea", Object.assign({ key: '4c077fd2d1ebc85adc594dba46e9394201a4a150', class: "native-textarea", ref: (el) => (this.nativeInput = el), id: inputId, disabled: disabled, autoCapitalize: this.autocapitalize, autoFocus: this.autofocus, enterKeyHint: this.enterkeyhint, inputMode: this.inputmode, minLength: this.minlength, maxLength: this.maxlength, name: this.name, placeholder: this.placeholder || '', readOnly: this.readonly, required: this.required, spellcheck: this.spellcheck, cols: this.cols, rows: this.rows, wrap: this.wrap, onInput: this.onInput, onChange: this.onChange, onBlur: this.onBlur, onFocus: this.onFocus, onKeyDown: this.onKeyDown, "aria-describedby": this.getHintTextID(), "aria-invalid": this.isInvalid ? 'true' : undefined }, this.inheritedAttributes), value)), h("div", { key: '7ce24ce1907d48437bf71a643e19534ec3a3a1c2', class: "end-slot-wrapper" }, h("slot", { key: 'ab613d63868ac280b6559511ec8e1bc61f208008', name: "end" }))), shouldRenderHighlight && h("div", { key: '47af23482b696315eec2849887326d2229391f80', class: "textarea-highlight" })), this.renderBottomContent()));
590
+ theme === 'ionic' && fill === 'outline' && h("div", { key: 'c8f68629935444bedaf41c8958e13fd1916a0871', class: "textarea-outline" }), h("div", { key: '56349914a8348214f9a663c768a3915fc70e21cd', class: "start-slot-wrapper" }, h("slot", { key: '8b399fd0f049f579f7af1183052614f459d52169', name: "start" })), h("div", { key: '5edec308a1ade5d4634ee5bae413e27a9f17e3cb', class: "native-wrapper", ref: (el) => (this.textareaWrapper = el), part: "container" }, h("textarea", Object.assign({ key: 'ac792e9d46e30bb0fe72b6e8f57880ff5114dff6', class: "native-textarea", part: "native", ref: (el) => (this.nativeInput = el), id: inputId, disabled: disabled, autoCapitalize: this.autocapitalize, autoFocus: this.autofocus, enterKeyHint: this.enterkeyhint, inputMode: this.inputmode, minLength: this.minlength, maxLength: this.maxlength, name: this.name, placeholder: this.placeholder || '', readOnly: this.readonly, required: this.required, spellcheck: this.spellcheck, cols: this.cols, rows: this.rows, wrap: this.wrap, onInput: this.onInput, onChange: this.onChange, onBlur: this.onBlur, onFocus: this.onFocus, onKeyDown: this.onKeyDown, "aria-describedby": this.getHintTextID(), "aria-invalid": this.isInvalid ? 'true' : undefined }, this.inheritedAttributes), value)), h("div", { key: '02e2a10f1f8fd6e05f457320cb90fade56cf06a9', class: "end-slot-wrapper" }, h("slot", { key: '4314c344b0054cafcb65358451afa2dbef5bd8ef', name: "end" }))), shouldRenderHighlight && h("div", { key: '94e8b3639665cf9c068abfd681e7fa4c515307f4', class: "textarea-highlight" })), this.renderBottomContent()));
522
591
  }
523
592
  static get is() { return "ion-textarea"; }
524
- static get encapsulation() { return "scoped"; }
593
+ static get encapsulation() { return "shadow"; }
594
+ static get delegatesFocus() { return true; }
595
+ static get formAssociated() { return true; }
525
596
  static get originalStyleUrls() {
526
597
  return {
527
598
  "ios": ["textarea.ios.scss"],
@@ -832,7 +903,7 @@ export class Textarea {
832
903
  },
833
904
  "getter": false,
834
905
  "setter": false,
835
- "reflect": false,
906
+ "reflect": true,
836
907
  "attribute": "required",
837
908
  "defaultValue": "false"
838
909
  },
@@ -1246,9 +1317,15 @@ export class Textarea {
1246
1317
  return [{
1247
1318
  "propName": "debounce",
1248
1319
  "methodName": "debounceChanged"
1320
+ }, {
1321
+ "propName": "disabled",
1322
+ "methodName": "disabledChanged"
1249
1323
  }, {
1250
1324
  "propName": "value",
1251
1325
  "methodName": "valueChanged"
1326
+ }, {
1327
+ "propName": "required",
1328
+ "methodName": "requiredChanged"
1252
1329
  }, {
1253
1330
  "propName": "dir",
1254
1331
  "methodName": "onDirChanged"
@@ -1263,5 +1340,6 @@ export class Textarea {
1263
1340
  "passive": false
1264
1341
  }];
1265
1342
  }
1343
+ static get attachInternalsMemberName() { return "internals"; }
1266
1344
  }
1267
1345
  let textareaIds = 0;
@@ -152,12 +152,12 @@
152
152
  background: initial;
153
153
  }
154
154
 
155
- :host-context(ion-item) {
155
+ :host(.in-item) {
156
156
  align-self: baseline;
157
157
  }
158
158
 
159
- :host-context(ion-item)[slot=start],
160
- :host-context(ion-item)[slot=end] {
159
+ :host(.in-item[slot=start]),
160
+ :host(.in-item[slot=end]) {
161
161
  width: auto;
162
162
  }
163
163
 
@@ -334,6 +334,7 @@
334
334
  display: flex;
335
335
  width: 100%;
336
336
  min-height: inherit;
337
+ box-sizing: border-box;
337
338
  }
338
339
 
339
340
  :host(.ion-touched.ion-invalid) {
@@ -438,6 +439,10 @@
438
439
  overflow: hidden;
439
440
  }
440
441
 
442
+ .textarea-outline {
443
+ box-sizing: border-box;
444
+ }
445
+
441
446
  /**
442
447
  * If no label text is placed into the slot
443
448
  * then the element should be hidden otherwise
@@ -547,17 +552,6 @@
547
552
  opacity: 1;
548
553
  }
549
554
 
550
- /**
551
- * When the rows attribute is set, the textarea should not force a min-height,
552
- * but rather respect the natural height of the textarea. Specially when
553
- * rows is set to 1.
554
- */
555
- :host(.textarea-fill-outline.sc-ion-textarea-md-h[rows]),
556
- :host(.textarea-label-placement-stacked[rows]),
557
- :host(.textarea-label-placement-floating[rows]) {
558
- min-height: auto;
559
- }
560
-
561
555
  .start-slot-wrapper,
562
556
  .end-slot-wrapper {
563
557
  display: flex;
@@ -1345,6 +1339,7 @@
1345
1339
  :host(.textarea-fill-outline) .textarea-outline-end {
1346
1340
  border-top: var(--border-width) var(--border-style) var(--border-color);
1347
1341
  border-bottom: var(--border-width) var(--border-style) var(--border-color);
1342
+ box-sizing: border-box;
1348
1343
  }
1349
1344
 
1350
1345
  /**
@@ -10,9 +10,9 @@ import { getIonTheme } from "../../global/ionic-global";
10
10
  export class Thumbnail {
11
11
  render() {
12
12
  const theme = getIonTheme(this);
13
- return (h(Host, { key: '670c8628ac609877cf628e7301223a43d808535b', class: {
13
+ return (h(Host, { key: '6053cf163155d4268dad4fc81ffc6bbc70d75659', class: {
14
14
  [theme]: true,
15
- } }, h("slot", { key: 'e766b13c6cf4167edfeda2d21654c1e778125955' })));
15
+ } }, h("slot", { key: 'b7afb5835bce7c7ed9e5cf44758bbe2d802e1271' })));
16
16
  }
17
17
  static get is() { return "ion-thumbnail"; }
18
18
  static get encapsulation() { return "shadow"; }
@@ -27,11 +27,11 @@ export class ToolbarTitle {
27
27
  render() {
28
28
  const theme = getIonTheme(this);
29
29
  const size = this.getSize();
30
- return (h(Host, { key: '770c002757fc29f57277da78e25ac426346eaed9', class: createColorClasses(this.color, {
30
+ return (h(Host, { key: '8db3e5f9dbd8b1762a9919eaeef29c98649dfb25', class: createColorClasses(this.color, {
31
31
  [theme]: true,
32
32
  [`title-${size}`]: true,
33
33
  'title-rtl': document.dir === 'rtl',
34
- }) }, h("div", { key: 'fb2d65cc98575d310f9dbcf8d5b2b8a8d6f87e57', class: "toolbar-title" }, h("slot", { key: '73d0c525b1acde370a1460008e7c0145ae5d7e4b' }))));
34
+ }) }, h("div", { key: 'a31ebae2c494a51d2145eec69d0b1bc635108a01', class: "toolbar-title" }, h("slot", { key: 'f5975b44b3e3afbf98dcbdb53fc78447b49407b3' }))));
35
35
  }
36
36
  static get is() { return "ion-title"; }
37
37
  static get encapsulation() { return "shadow"; }
@@ -437,9 +437,9 @@ export class Toast {
437
437
  if (layout === 'stacked' && startButtons.length > 0 && endButtons.length > 0) {
438
438
  printIonWarning('[ion-toast] - This toast is using start and end buttons with the stacked toast layout. We recommend following the best practice of using either start or end buttons with the stacked toast layout.', el);
439
439
  }
440
- return (h(Host, Object.assign({ key: '88e2d57b1de7194aa5e62eb9b4c7fe555b97060d', tabindex: "-1" }, this.htmlAttributes, { style: {
440
+ return (h(Host, Object.assign({ key: '3f25e3c14197723e0c97edb71ddeeccb4f9143b3', tabindex: "-1" }, this.htmlAttributes, { style: {
441
441
  zIndex: `${60000 + this.overlayIndex}`,
442
- }, class: createColorClasses(this.color, Object.assign(Object.assign({ [mode]: true, [theme]: true }, getClassMap(this.cssClass)), { 'overlay-hidden': true, 'toast-translucent': this.translucent, [`toast-shape-${shape}`]: shape !== undefined, [`toast-hue-${hue}`]: hue !== undefined })), onIonToastWillDismiss: this.dispatchCancelHandler }), h("div", { key: 'f9764be0cddf6188cbf1cef202ddbcb805a093b3', class: wrapperClass }, h("div", { key: 'b202a52eac3d3087c11834e851d4e7e92e762399', class: "toast-container", part: "container" }, this.renderButtons(startButtons, 'start'), this.icon !== undefined && (h("ion-icon", { key: '8009f48afeb838dcc9fc3b01c3e4062c1d323347', class: "toast-icon", part: "icon", icon: this.icon, lazy: false, "aria-hidden": "true" })), h("div", { key: '2767dee244fa4576ec5163b274b89384692be753', class: "toast-content", role: "status", "aria-atomic": "true", "aria-live": "polite" }, !revealContentToScreenReader && header !== undefined && this.renderHeader('oldHeader', 'true'), !revealContentToScreenReader && message !== undefined && this.renderToastMessage('oldMessage', 'true'), revealContentToScreenReader && header !== undefined && this.renderHeader('header'), revealContentToScreenReader && message !== undefined && this.renderToastMessage('header')), this.renderButtons(endButtons, 'end')))));
442
+ }, class: createColorClasses(this.color, Object.assign(Object.assign({ [mode]: true, [theme]: true }, getClassMap(this.cssClass)), { 'overlay-hidden': true, 'toast-translucent': this.translucent, [`toast-shape-${shape}`]: shape !== undefined, [`toast-hue-${hue}`]: hue !== undefined })), onIonToastWillDismiss: this.dispatchCancelHandler }), h("div", { key: 'cec09872b7e08429a62e5cb821e072fa6259e63a', class: wrapperClass }, h("div", { key: '8179d7a3c8b27536e37886a21293d1a6add60306', class: "toast-container", part: "container" }, this.renderButtons(startButtons, 'start'), this.icon !== undefined && (h("ion-icon", { key: 'ef87a58440d914e4c55b8b3ecaac45f983f35daf', class: "toast-icon", part: "icon", icon: this.icon, lazy: false, "aria-hidden": "true" })), h("div", { key: '56bca03e8501ad921cf2de37faace99a4f59cc71', class: "toast-content", role: "status", "aria-atomic": "true", "aria-live": "polite" }, !revealContentToScreenReader && header !== undefined && this.renderHeader('oldHeader', 'true'), !revealContentToScreenReader && message !== undefined && this.renderToastMessage('oldMessage', 'true'), revealContentToScreenReader && header !== undefined && this.renderHeader('header'), revealContentToScreenReader && message !== undefined && this.renderToastMessage('header')), this.renderButtons(endButtons, 'end')))));
443
443
  }
444
444
  static get is() { return "ion-toast"; }
445
445
  static get encapsulation() { return "shadow"; }
@@ -338,7 +338,7 @@ export class Toggle {
338
338
  const rtl = isRTL(el) ? 'rtl' : 'ltr';
339
339
  const isIonicTheme = theme === 'ionic';
340
340
  renderHiddenInput(true, el, name, checked ? value : '', disabled);
341
- return (h(Host, { key: 'c622d6548e5249afefe43fe4a3eebfacc13c46e3', role: "switch", "aria-checked": `${checked}`, "aria-describedby": this.hintTextId, "aria-invalid": this.isInvalid ? 'true' : undefined, onClick: this.onClick, "aria-labelledby": hasLabel ? inputLabelId : null, "aria-label": inheritedAttributes['aria-label'] || null, "aria-disabled": disabled ? 'true' : null, "aria-required": required ? 'true' : undefined, tabindex: disabled ? undefined : 0, onKeyDown: this.onKeyDown, onFocus: this.onFocus, onBlur: this.onBlur, class: createColorClasses(color, {
341
+ return (h(Host, { key: 'b12951146a79d3839e6263e91e747398a0fa901d', role: "switch", "aria-checked": `${checked}`, "aria-describedby": this.hintTextId, "aria-invalid": this.isInvalid ? 'true' : undefined, onClick: this.onClick, "aria-labelledby": hasLabel ? inputLabelId : null, "aria-label": inheritedAttributes['aria-label'] || null, "aria-disabled": disabled ? 'true' : null, "aria-required": required ? 'true' : undefined, tabindex: disabled ? undefined : 0, onKeyDown: this.onKeyDown, onFocus: this.onFocus, onBlur: this.onBlur, class: createColorClasses(color, {
342
342
  [theme]: true,
343
343
  'in-item': hostContext('ion-item', el),
344
344
  'toggle-activated': activated,
@@ -350,10 +350,10 @@ export class Toggle {
350
350
  [`toggle-${rtl}`]: true,
351
351
  'ion-activatable': isIonicTheme,
352
352
  'ion-focusable': isIonicTheme,
353
- }) }, h("label", { key: '5cb15fd4884ec35887859ba6db3609ef9e089f39', class: "toggle-wrapper", htmlFor: inputId }, h("input", Object.assign({ key: '81b24cc830074850bf22f0fcd8bc4c6b0b95ae02', type: "checkbox", role: "switch", "aria-checked": `${checked}`, checked: checked, disabled: disabled, id: inputId, required: required }, inheritedAttributes)), h("div", { key: '4700c06a080895c5421b7c1cd139cbda61fcd2f1', class: {
353
+ }) }, h("label", { key: 'cf1d27243bf9bdd5bafaf6d86b76beb311b5e01c', class: "toggle-wrapper", htmlFor: inputId }, h("input", Object.assign({ key: 'b3eb0f146836f5994c15bf1fd67a79f72b9414f7', type: "checkbox", role: "switch", "aria-checked": `${checked}`, checked: checked, disabled: disabled, id: inputId, required: required }, inheritedAttributes)), h("div", { key: '56ddcfd6452f30fd6b38d0fd85be3ec966aa120b', class: {
354
354
  'label-text-wrapper': true,
355
355
  'label-text-wrapper-hidden': !hasLabel,
356
- }, part: "label", id: inputLabelId, onClick: this.onDivLabelClick }, h("slot", { key: '5af5c0e3601736090cfed56c3c88e08193654561' }), this.renderHintText()), h("div", { key: 'f1004334510fea20be01f2170627fa1839f42be5', class: "native-wrapper" }, this.renderToggleControl()))));
356
+ }, part: "label", id: inputLabelId, onClick: this.onDivLabelClick }, h("slot", { key: '706e5b667ee242fb1afb3e4afa613f9798fbe25b' }), this.renderHintText()), h("div", { key: '255ccd7d60f7d78b4eba8d380b303a72093e9d16', class: "native-wrapper" }, this.renderToggleControl()))));
357
357
  }
358
358
  static get is() { return "ion-toggle"; }
359
359
  static get encapsulation() { return "shadow"; }
@@ -207,10 +207,10 @@ export class Toolbar {
207
207
  this.childrenStyles.forEach((style) => {
208
208
  Object.assign(childStyles, style);
209
209
  });
210
- return (h(Host, { key: '2c88dcfd26c7d24aaf479d1d993b5562d3619f6b', class: Object.assign(Object.assign({}, createColorClasses(this.color, {
210
+ return (h(Host, { key: '6f52a5408379012843d0b93ac20c25b868e0211c', class: Object.assign(Object.assign({}, createColorClasses(this.color, {
211
211
  [theme]: true,
212
212
  'in-toolbar': hostContext('ion-toolbar', this.el),
213
- })), childStyles) }, h("div", { key: 'b0ee3cb68417c5013d7dd61b5d57bce29f575bad', class: "toolbar-background", part: "background" }), h("div", { key: '0626d61b71f5d0ba1ee37508cffbd63034f7b292', class: "toolbar-container", part: "container" }, h("slot", { key: 'e7a540e310d55ec6a1b61bee70bb285a75a3f019', name: "start", onSlotchange: () => this.updateSlotClasses }), h("slot", { key: '0f9e4d832691123209abca302532825efe5f7c98', name: "secondary", onSlotchange: () => this.updateSlotClasses }), h("div", { key: 'ff8fa2ab1ed25ed95dc2a889e07d9f2e85b7245d', class: "toolbar-content", part: "content" }, h("slot", { key: '78cc3ba30a35a71f464f7256343e2a523740a8e9' })), h("slot", { key: 'db88e674acc2befc1d4e5f2c2b03b48dde54d12e', name: "primary", onSlotchange: () => this.updateSlotClasses }), h("slot", { key: 'd8fd9de870c5d77a139442d38565686121c68887', name: "end", onSlotchange: () => this.updateSlotClasses }))));
213
+ })), childStyles) }, h("div", { key: '8f79b04f7c26edb4d64b88d1e1a69ee6e4ab8773', class: "toolbar-background", part: "background" }), h("div", { key: '8a682653ea75f07fa583d9b7cf38850294e83448', class: "toolbar-container", part: "container" }, h("slot", { key: '1a4e3289bdc3802cbabdd99d4bd5ab45e10846d8', name: "start", onSlotchange: () => this.updateSlotClasses }), h("slot", { key: '5578aaf1d8bf6dba08ab4ac9ccd9b8d8fe6c8ff1', name: "secondary", onSlotchange: () => this.updateSlotClasses }), h("div", { key: 'd4ba11c8daf43ed164a9c89dafdd96c5d2b50a35', class: "toolbar-content", part: "content" }, h("slot", { key: '994952702fe18216044d10a96abbf9cf071612e3' })), h("slot", { key: '2e07d6585687764a0a24bbc1b2f456aec30bfea7', name: "primary", onSlotchange: () => this.updateSlotClasses }), h("slot", { key: 'ebcb8dcde1202d6ced4c251a3b78c30b1153849f', name: "end", onSlotchange: () => this.updateSlotClasses }))));
214
214
  }
215
215
  static get is() { return "ion-toolbar"; }
216
216
  static get encapsulation() { return "shadow"; }
@@ -14,7 +14,7 @@ import { focusVisibleElement } from "./helpers";
14
14
  * Note: We need this distinction because `disabled="false"` is
15
15
  * valid usage for the disabled property on ion-button.
16
16
  */
17
- export const focusableQueryString = '[tabindex]:not([tabindex^="-"]):not([hidden]):not([disabled]), input:not([type=hidden]):not([tabindex^="-"]):not([hidden]):not([disabled]), textarea:not([tabindex^="-"]):not([hidden]):not([disabled]), button:not([tabindex^="-"]):not([hidden]):not([disabled]), select:not([tabindex^="-"]):not([hidden]):not([disabled]), ion-checkbox:not([tabindex^="-"]):not([hidden]):not([disabled]), ion-radio:not([tabindex^="-"]):not([hidden]):not([disabled]), .ion-focusable:not([tabindex^="-"]):not([hidden]):not([disabled]), .ion-focusable[disabled="false"]:not([tabindex^="-"]):not([hidden])';
17
+ export const focusableQueryString = '[tabindex]:not([tabindex^="-"]):not([hidden]):not([disabled]), input:not([type=hidden]):not([tabindex^="-"]):not([hidden]):not([disabled]), textarea:not([tabindex^="-"]):not([hidden]):not([disabled]), button:not([tabindex^="-"]):not([hidden]):not([disabled]), select:not([tabindex^="-"]):not([hidden]):not([disabled]), ion-checkbox:not([tabindex^="-"]):not([hidden]):not([disabled]), ion-radio:not([tabindex^="-"]):not([hidden]):not([disabled]), ion-textarea:not([tabindex^="-"]):not([hidden]):not([disabled]), .ion-focusable:not([tabindex^="-"]):not([hidden]):not([disabled]), .ion-focusable[disabled="false"]:not([tabindex^="-"]):not([hidden])';
18
18
  /**
19
19
  * Focuses the first descendant in a context
20
20
  * that can receive focus. If none exists,
@@ -66,7 +66,18 @@ const focusElementInContext = (hostToFocus, fallbackElement) => {
66
66
  const shadowRoot = hostToFocus === null || hostToFocus === void 0 ? void 0 : hostToFocus.shadowRoot;
67
67
  if (shadowRoot) {
68
68
  // If there are no inner focusable elements, just focus the host element.
69
- elementToFocus = shadowRoot.querySelector(focusableQueryString) || hostToFocus;
69
+ const innerFocusable = shadowRoot.querySelector(focusableQueryString);
70
+ // If the host has a setFocus() method, use it to delegate focus properly.
71
+ // This is needed for shadow DOM components like ion-textarea that override
72
+ // focus() to delegate to their inner native elements.
73
+ const hasSetFocus = typeof hostToFocus.setFocus === 'function';
74
+ if (innerFocusable && hasSetFocus) {
75
+ // Keep the host element so we can call setFocus() on it
76
+ elementToFocus = hostToFocus;
77
+ }
78
+ else {
79
+ elementToFocus = innerFocusable || hostToFocus;
80
+ }
70
81
  }
71
82
  if (elementToFocus) {
72
83
  const radioGroup = elementToFocus.closest('ion-radio-group');
@@ -13,3 +13,34 @@ export const checkInvalidState = (el) => {
13
13
  const hasIonInvalid = el.classList.contains('ion-invalid');
14
14
  return hasIonTouched && hasIonInvalid;
15
15
  };
16
+ export const getValidityFlags = (validity) => {
17
+ return {
18
+ badInput: validity.badInput,
19
+ customError: validity.customError,
20
+ patternMismatch: validity.patternMismatch,
21
+ rangeOverflow: validity.rangeOverflow,
22
+ rangeUnderflow: validity.rangeUnderflow,
23
+ stepMismatch: validity.stepMismatch,
24
+ tooLong: validity.tooLong,
25
+ tooShort: validity.tooShort,
26
+ typeMismatch: validity.typeMismatch,
27
+ valueMissing: validity.valueMissing,
28
+ };
29
+ };
30
+ /**
31
+ * Reports the validity state of a native form element to ElementInternals.
32
+ * This delegates to the native element's built-in validation, which automatically
33
+ * handles required, minlength, maxlength, and other constraints.
34
+ */
35
+ export const reportValidityToElementInternals = (nativeElement, internals) => {
36
+ if (!(nativeElement === null || nativeElement === void 0 ? void 0 : nativeElement.validity)) {
37
+ return;
38
+ }
39
+ if (nativeElement.validity.valid) {
40
+ internals.setValidity({});
41
+ }
42
+ else {
43
+ const validityFlags = getValidityFlags(nativeElement.validity);
44
+ internals.setValidity(validityFlags, nativeElement.validationMessage, nativeElement);
45
+ }
46
+ };
@@ -225,10 +225,24 @@ export const focusVisibleElement = (el) => {
225
225
  * however, there are times when we need to manually control
226
226
  * this behavior so we call the `setFocus` method on ion-app
227
227
  * which will let us explicitly set the elements to focus.
228
+ *
229
+ * Note: The element passed to this function might be an inner
230
+ * focusable element (e.g., a native <button> inside ion-button's
231
+ * shadow root). If so, we need to find the host element that has
232
+ * the ion-focusable class to pass to setFocus.
228
233
  */
229
- if (el.classList.contains('ion-focusable')) {
234
+ let elToFocus = el;
235
+ // If the element doesn't have ion-focusable, check if it's inside
236
+ // a shadow root and use the host element instead
237
+ if (!el.classList.contains('ion-focusable')) {
238
+ const rootNode = el.getRootNode();
239
+ if (rootNode instanceof ShadowRoot && rootNode.host instanceof HTMLElement) {
240
+ elToFocus = rootNode.host;
241
+ }
242
+ }
243
+ if (elToFocus.classList.contains('ion-focusable')) {
230
244
  const appRootSelector = config.get('appRootSelector', 'ion-app');
231
- const app = el.closest(appRootSelector);
245
+ const app = elToFocus.closest(appRootSelector);
232
246
  if (app) {
233
247
  if (appRootSelector === 'ion-app') {
234
248
  /**
@@ -237,7 +251,7 @@ export const focusVisibleElement = (el) => {
237
251
  * focus-visible utility is attached to the app root
238
252
  * and will handle setting focus on the correct element.
239
253
  */
240
- app.setFocus([el]);
254
+ app.setFocus([elToFocus]);
241
255
  }
242
256
  else {
243
257
  /**
@@ -254,7 +268,7 @@ export const focusVisibleElement = (el) => {
254
268
  * The focus-visible utility is used to set focus on an
255
269
  * element that uses `ion-focusable`.
256
270
  */
257
- focusElements([el]);
271
+ focusElements([elToFocus]);
258
272
  });
259
273
  }
260
274
  }
@@ -319,6 +319,86 @@ const connectListeners = (doc) => {
319
319
  doc.addEventListener('focus', (ev) => {
320
320
  trapKeyboardFocus(ev, doc);
321
321
  }, true);
322
+ // Listen for keydown events to intercept Tab navigation.
323
+ // This is needed for Safari and Firefox which may skip focusable
324
+ // elements or allow focus to escape the overlay.
325
+ // It also ensures proper focus delegation for shadow DOM elements
326
+ // like ion-textarea.
327
+ doc.addEventListener('keydown', (ev) => {
328
+ var _a, _b, _c;
329
+ if (ev.key !== 'Tab' && ev.key !== 'Alt+Tab')
330
+ return;
331
+ const lastOverlay = getPresentedOverlay(doc, 'ion-alert,ion-action-sheet,ion-loading,ion-modal,ion-picker-legacy,ion-popover');
332
+ if (!lastOverlay || lastOverlay.classList.contains(FOCUS_TRAP_DISABLE_CLASS))
333
+ return;
334
+ const activeElement = doc.activeElement;
335
+ if (activeElement === lastOverlay) {
336
+ ev.preventDefault();
337
+ focusFirstDescendant(lastOverlay);
338
+ return;
339
+ }
340
+ // Check if activeElement is inside the overlay (including shadow DOM)
341
+ const isInsideOverlay = activeElement
342
+ ? lastOverlay.contains(activeElement) ||
343
+ (activeElement.getRootNode() instanceof ShadowRoot &&
344
+ lastOverlay.contains(activeElement.getRootNode().host)) ||
345
+ ((_b = (_a = lastOverlay.shadowRoot) === null || _a === void 0 ? void 0 : _a.contains(activeElement)) !== null && _b !== void 0 ? _b : false)
346
+ : false;
347
+ if (!isInsideOverlay)
348
+ return;
349
+ // Get all focusable elements from both light and shadow DOM
350
+ const allFocusable = [
351
+ ...lastOverlay.querySelectorAll(focusableQueryString),
352
+ ...(((_c = lastOverlay.shadowRoot) === null || _c === void 0 ? void 0 : _c.querySelectorAll(focusableQueryString)) || []),
353
+ ];
354
+ if (allFocusable.length === 0) {
355
+ ev.preventDefault();
356
+ return;
357
+ }
358
+ // Find current element's index (accounting for shadow DOM)
359
+ const currentIndex = activeElement
360
+ ? allFocusable.findIndex((el) => {
361
+ var _a;
362
+ if (el === activeElement)
363
+ return true;
364
+ if ((_a = el.shadowRoot) === null || _a === void 0 ? void 0 : _a.contains(activeElement))
365
+ return true;
366
+ const rootNode = activeElement.getRootNode();
367
+ return rootNode instanceof ShadowRoot && rootNode.host === el;
368
+ })
369
+ : -1;
370
+ ev.preventDefault();
371
+ // Helper to focus an element, handling shadow DOM properly
372
+ const focusElement = (element) => {
373
+ const shadowRoot = element.shadowRoot;
374
+ if (shadowRoot) {
375
+ const innerFocusable = shadowRoot.querySelector(focusableQueryString);
376
+ if (innerFocusable && typeof element.setFocus !== 'function') {
377
+ focusVisibleElement(innerFocusable);
378
+ return;
379
+ }
380
+ }
381
+ focusVisibleElement(element);
382
+ };
383
+ if (ev.shiftKey) {
384
+ // Shift+Tab: previous element, wrap to last if at first
385
+ if (currentIndex <= 0) {
386
+ focusLastDescendant(lastOverlay);
387
+ }
388
+ else {
389
+ focusElement(allFocusable[currentIndex - 1]);
390
+ }
391
+ }
392
+ else {
393
+ // Tab: next element, wrap to first if at last
394
+ if (currentIndex < 0 || currentIndex >= allFocusable.length - 1) {
395
+ focusFirstDescendant(lastOverlay);
396
+ }
397
+ else {
398
+ focusElement(allFocusable[currentIndex + 1]);
399
+ }
400
+ }
401
+ }, true);
322
402
  // handle back-button click
323
403
  doc.addEventListener('ionBackButton', (ev) => {
324
404
  const lastOverlay = getPresentedOverlay(doc);
@@ -1,8 +1,32 @@
1
1
  /*!
2
2
  * (C) Ionic http://ionicframework.com - MIT License
3
3
  */
4
+ /**
5
+ * Checks if an element has a parent matching the specified selector.
6
+ * This handles an element in both light DOM and shadow DOM contexts.
7
+ * @param selector The parent selector to check for (e.g., 'ion-datetime'
8
+ * or 'ion-toolbar[color]').
9
+ * @param el The element to check.
10
+ * @returns `true` if the element has a parent matching the specified selector,
11
+ * `false` otherwise.
12
+ */
4
13
  export const hostContext = (selector, el) => {
5
- return el.closest(selector) !== null;
14
+ // Check the light DOM first
15
+ if (el.closest(selector) !== null) {
16
+ return true;
17
+ }
18
+ // For attribute or class selectors (e.g., 'ion-toolbar[color]' or
19
+ // 'ion-toolbar.ion-color') we can only check light DOM since tagName
20
+ // doesn't include attributes or classes.
21
+ if (selector.includes('[') || selector.includes('.')) {
22
+ return false;
23
+ }
24
+ // Check the shadow DOM by looking at the shadow root host and
25
+ // converting the selector to uppercase to compare with tagName
26
+ const upperCaseTagName = selector.toUpperCase();
27
+ const rootNode = el.getRootNode();
28
+ const shadowHost = rootNode instanceof ShadowRoot ? rootNode.host : null;
29
+ return (shadowHost === null || shadowHost === void 0 ? void 0 : shadowHost.tagName) === upperCaseTagName;
6
30
  };
7
31
  /**
8
32
  * Create the mode and color classes for the component based on the classes passed in