@ionic/core 8.8.19-dev.11786730389.1a1927bf → 8.8.19-dev.11786735826.1fad7c0a

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 (289) hide show
  1. package/components/ion-action-sheet.js +1 -1
  2. package/components/ion-alert.js +1 -1
  3. package/components/ion-back-button.js +1 -1
  4. package/components/ion-button.js +1 -1
  5. package/components/ion-card.js +1 -1
  6. package/components/ion-chip.js +1 -1
  7. package/components/ion-datetime-button.js +1 -1
  8. package/components/ion-datetime.js +1 -1
  9. package/components/ion-fab-button.js +1 -1
  10. package/components/ion-infinite-scroll-content.js +1 -1
  11. package/components/ion-input-otp.js +1 -1
  12. package/components/ion-input-password-toggle.js +1 -1
  13. package/components/ion-input.js +1 -1
  14. package/components/ion-item-divider.js +1 -1
  15. package/components/ion-item-group.js +1 -1
  16. package/components/ion-item-option.js +1 -1
  17. package/components/ion-item-options.js +1 -1
  18. package/components/ion-item-sliding.js +1 -1
  19. package/components/ion-item.js +1 -1
  20. package/components/ion-label.js +1 -1
  21. package/components/ion-list-header.js +1 -1
  22. package/components/ion-list.js +1 -1
  23. package/components/ion-loading.js +1 -1
  24. package/components/ion-menu-button.js +1 -1
  25. package/components/ion-menu-toggle.js +1 -1
  26. package/components/ion-menu.js +1 -1
  27. package/components/ion-modal.js +1 -1
  28. package/components/ion-nav-link.js +1 -1
  29. package/components/ion-nav.js +1 -1
  30. package/components/ion-note.js +1 -1
  31. package/components/ion-picker-column-option.js +1 -1
  32. package/components/ion-popover.js +1 -1
  33. package/components/ion-progress-bar.js +1 -1
  34. package/components/ion-radio-group.js +1 -1
  35. package/components/ion-radio.js +1 -1
  36. package/components/ion-range.js +1 -1
  37. package/components/ion-refresher-content.js +1 -1
  38. package/components/ion-refresher.js +1 -1
  39. package/components/ion-reorder-group.js +1 -1
  40. package/components/ion-reorder.js +1 -1
  41. package/components/ion-ripple-effect.js +1 -1
  42. package/components/ion-router-link.js +1 -1
  43. package/components/ion-router-outlet.js +1 -1
  44. package/components/ion-row.js +1 -1
  45. package/components/ion-searchbar.js +1 -1
  46. package/components/ion-segment-button.js +1 -1
  47. package/components/ion-segment-content.js +1 -1
  48. package/components/ion-segment-view.js +1 -1
  49. package/components/ion-segment.js +1 -1
  50. package/components/ion-select-modal.js +1 -1
  51. package/components/ion-select-option.js +1 -1
  52. package/components/ion-select-popover.js +1 -1
  53. package/components/ion-select.js +1 -1
  54. package/components/ion-skeleton-text.js +1 -1
  55. package/components/ion-spinner.js +1 -1
  56. package/components/ion-split-pane.js +1 -1
  57. package/components/ion-tab-bar.js +1 -1
  58. package/components/ion-tab-button.js +1 -1
  59. package/components/ion-tab.js +1 -1
  60. package/components/ion-tabs.js +1 -1
  61. package/components/ion-text.js +1 -1
  62. package/components/ion-textarea.js +1 -1
  63. package/components/ion-thumbnail.js +1 -1
  64. package/components/ion-title.js +1 -1
  65. package/components/ion-toast.js +1 -1
  66. package/components/ion-toggle.js +1 -1
  67. package/components/ion-toolbar.js +1 -1
  68. package/components/{p-C1O9GEug.js → p--m5cCjbK.js} +1 -1
  69. package/components/{p-CfnGxjv-.js → p-B4uHHhPK.js} +1 -1
  70. package/components/{p-BxUIQcD9.js → p-BOvLNVKq.js} +1 -1
  71. package/components/{p-D_XD0pVT.js → p-BWBigMsI.js} +1 -1
  72. package/components/{p-xOjr4bwc.js → p-BZ4-QTes.js} +1 -1
  73. package/components/{p-tYCT3JGl.js → p-BjluhQMI.js} +1 -1
  74. package/components/{p-ClFYbgND.js → p-BlsIikdZ.js} +1 -1
  75. package/components/{p-Obm7si-x.js → p-Blug1Vxu.js} +1 -1
  76. package/components/{p-DTY4otpr.js → p-C91npEel.js} +1 -1
  77. package/components/{p-CVnwvOBD.js → p-CVb3x_r3.js} +1 -1
  78. package/components/{p-B6dUPQXq.js → p-CWLrHG8Y.js} +1 -1
  79. package/components/{p-0Pyit076.js → p-CfnNZz_d.js} +1 -1
  80. package/components/{p-DyePCNGr.js → p-DKrhJJV0.js} +1 -1
  81. package/components/p-DSzSbVP2.js +4 -0
  82. package/components/{p-BsVxQGUT.js → p-DgZOZQjJ.js} +1 -1
  83. package/components/{p-BO4sUqUv.js → p-Dmd2xqCe.js} +1 -1
  84. package/components/{p-83oP9gzn.js → p-GG5GhznE.js} +1 -1
  85. package/components/{p-Bc4wROfM.js → p-UQSiXX2Z.js} +1 -1
  86. package/components/{p-Dm7h4Nyv.js → p-qT1szVjw.js} +1 -1
  87. package/components/p-ypuYdSDB.js +4 -0
  88. package/dist/cjs/input.utils-BZdMWVrt.js +35 -0
  89. package/dist/cjs/ion-app_8.cjs.entry.js +5 -5
  90. package/dist/cjs/ion-avatar_3.cjs.entry.js +1 -1
  91. package/dist/cjs/ion-col_3.cjs.entry.js +1 -1
  92. package/dist/cjs/ion-input-otp.cjs.entry.js +3 -3
  93. package/dist/cjs/ion-input-password-toggle.cjs.entry.js +3 -3
  94. package/dist/cjs/ion-input.cjs.entry.js +42 -56
  95. package/dist/cjs/ion-item-option_3.cjs.entry.js +4 -4
  96. package/dist/cjs/ion-item_8.cjs.entry.js +12 -12
  97. package/dist/cjs/ion-loading.cjs.entry.js +2 -2
  98. package/dist/cjs/ion-menu_3.cjs.entry.js +6 -6
  99. package/dist/cjs/ion-modal.cjs.entry.js +4 -4
  100. package/dist/cjs/ion-nav_2.cjs.entry.js +2 -2
  101. package/dist/cjs/ion-picker-column-option.cjs.entry.js +2 -2
  102. package/dist/cjs/ion-popover.cjs.entry.js +2 -2
  103. package/dist/cjs/ion-progress-bar.cjs.entry.js +1 -1
  104. package/dist/cjs/ion-radio_2.cjs.entry.js +4 -4
  105. package/dist/cjs/ion-range.cjs.entry.js +3 -3
  106. package/dist/cjs/ion-refresher_2.cjs.entry.js +2 -2
  107. package/dist/cjs/ion-reorder_2.cjs.entry.js +2 -2
  108. package/dist/cjs/ion-ripple-effect.cjs.entry.js +1 -1
  109. package/dist/cjs/ion-route_4.cjs.entry.js +2 -2
  110. package/dist/cjs/ion-searchbar.cjs.entry.js +4 -4
  111. package/dist/cjs/ion-segment-content.cjs.entry.js +1 -1
  112. package/dist/cjs/ion-segment-view.cjs.entry.js +2 -2
  113. package/dist/cjs/ion-segment_2.cjs.entry.js +4 -4
  114. package/dist/cjs/ion-select-modal.cjs.entry.js +1 -1
  115. package/dist/cjs/ion-select_3.cjs.entry.js +41 -59
  116. package/dist/cjs/ion-spinner.cjs.entry.js +1 -1
  117. package/dist/cjs/ion-split-pane.cjs.entry.js +2 -2
  118. package/dist/cjs/ion-tab-bar_2.cjs.entry.js +4 -4
  119. package/dist/cjs/ion-tab_2.cjs.entry.js +3 -3
  120. package/dist/cjs/ion-text.cjs.entry.js +2 -2
  121. package/dist/cjs/ion-textarea.cjs.entry.js +44 -55
  122. package/dist/cjs/ion-toast.cjs.entry.js +2 -2
  123. package/dist/cjs/ion-toggle.cjs.entry.js +4 -4
  124. package/dist/cjs/slot-mutation-controller-CgTGFqlW.js +397 -0
  125. package/dist/collection/components/input/input.ios.css +56 -24
  126. package/dist/collection/components/input/input.js +36 -51
  127. package/dist/collection/components/input/input.md.css +78 -41
  128. package/dist/collection/components/input-otp/input-otp.js +3 -3
  129. package/dist/collection/components/input-password-toggle/input-password-toggle.js +3 -3
  130. package/dist/collection/components/item-divider/item-divider.js +2 -2
  131. package/dist/collection/components/item-group/item-group.js +1 -1
  132. package/dist/collection/components/item-option/item-option.js +2 -2
  133. package/dist/collection/components/item-options/item-options.js +1 -1
  134. package/dist/collection/components/item-sliding/item-sliding.js +1 -1
  135. package/dist/collection/components/label/label.js +2 -2
  136. package/dist/collection/components/list/list.js +1 -1
  137. package/dist/collection/components/list-header/list-header.js +2 -2
  138. package/dist/collection/components/loading/loading.js +2 -2
  139. package/dist/collection/components/menu/menu.js +2 -2
  140. package/dist/collection/components/menu-button/menu-button.js +2 -2
  141. package/dist/collection/components/menu-toggle/menu-toggle.js +2 -2
  142. package/dist/collection/components/modal/modal.js +4 -4
  143. package/dist/collection/components/nav/nav.js +1 -1
  144. package/dist/collection/components/nav-link/nav-link.js +1 -1
  145. package/dist/collection/components/note/note.js +2 -2
  146. package/dist/collection/components/picker-column-option/picker-column-option.js +2 -2
  147. package/dist/collection/components/popover/popover.js +2 -2
  148. package/dist/collection/components/progress-bar/progress-bar.js +1 -1
  149. package/dist/collection/components/radio/radio.js +3 -3
  150. package/dist/collection/components/radio-group/radio-group.js +1 -1
  151. package/dist/collection/components/range/range.js +3 -3
  152. package/dist/collection/components/refresher/refresher.js +1 -1
  153. package/dist/collection/components/refresher-content/refresher-content.js +1 -1
  154. package/dist/collection/components/reorder/reorder.js +1 -1
  155. package/dist/collection/components/reorder-group/reorder-group.js +1 -1
  156. package/dist/collection/components/ripple-effect/ripple-effect.js +1 -1
  157. package/dist/collection/components/router-link/router-link.js +2 -2
  158. package/dist/collection/components/router-outlet/router-outlet.js +1 -1
  159. package/dist/collection/components/row/row.js +1 -1
  160. package/dist/collection/components/searchbar/searchbar.js +4 -4
  161. package/dist/collection/components/segment/segment.js +2 -2
  162. package/dist/collection/components/segment-button/segment-button.js +2 -2
  163. package/dist/collection/components/segment-content/segment-content.js +1 -1
  164. package/dist/collection/components/segment-view/segment-view.js +2 -2
  165. package/dist/collection/components/select/select.ios.css +63 -69
  166. package/dist/collection/components/select/select.js +40 -55
  167. package/dist/collection/components/select/select.md.css +85 -85
  168. package/dist/collection/components/select-modal/select-modal.js +1 -1
  169. package/dist/collection/components/select-option/select-option.js +1 -1
  170. package/dist/collection/components/select-popover/select-popover.js +1 -1
  171. package/dist/collection/components/skeleton-text/skeleton-text.js +2 -2
  172. package/dist/collection/components/spinner/spinner.js +1 -1
  173. package/dist/collection/components/split-pane/split-pane.js +2 -2
  174. package/dist/collection/components/tab/tab.js +2 -2
  175. package/dist/collection/components/tab-bar/tab-bar.js +2 -2
  176. package/dist/collection/components/tab-button/tab-button.js +2 -2
  177. package/dist/collection/components/tabs/tabs.js +1 -1
  178. package/dist/collection/components/text/text.js +2 -2
  179. package/dist/collection/components/textarea/textarea.ios.css +94 -62
  180. package/dist/collection/components/textarea/textarea.js +39 -51
  181. package/dist/collection/components/textarea/textarea.md.css +103 -77
  182. package/dist/collection/components/thumbnail/thumbnail.js +1 -1
  183. package/dist/collection/components/title/title.js +2 -2
  184. package/dist/collection/components/toast/toast.js +2 -2
  185. package/dist/collection/components/toggle/toggle.js +3 -3
  186. package/dist/collection/components/toolbar/toolbar.js +2 -2
  187. package/dist/collection/utils/forms/index.js +1 -0
  188. package/dist/collection/utils/forms/start-container-controller.js +132 -0
  189. package/dist/docs.json +22 -6
  190. package/dist/esm/input.utils-B1ValN_N.js +33 -0
  191. package/dist/esm/ion-app_8.entry.js +5 -5
  192. package/dist/esm/ion-avatar_3.entry.js +1 -1
  193. package/dist/esm/ion-col_3.entry.js +1 -1
  194. package/dist/esm/ion-input-otp.entry.js +3 -3
  195. package/dist/esm/ion-input-password-toggle.entry.js +3 -3
  196. package/dist/esm/ion-input.entry.js +40 -54
  197. package/dist/esm/ion-item-option_3.entry.js +4 -4
  198. package/dist/esm/ion-item_8.entry.js +12 -12
  199. package/dist/esm/ion-loading.entry.js +2 -2
  200. package/dist/esm/ion-menu_3.entry.js +6 -6
  201. package/dist/esm/ion-modal.entry.js +4 -4
  202. package/dist/esm/ion-nav_2.entry.js +2 -2
  203. package/dist/esm/ion-picker-column-option.entry.js +2 -2
  204. package/dist/esm/ion-popover.entry.js +2 -2
  205. package/dist/esm/ion-progress-bar.entry.js +1 -1
  206. package/dist/esm/ion-radio_2.entry.js +4 -4
  207. package/dist/esm/ion-range.entry.js +3 -3
  208. package/dist/esm/ion-refresher_2.entry.js +2 -2
  209. package/dist/esm/ion-reorder_2.entry.js +2 -2
  210. package/dist/esm/ion-ripple-effect.entry.js +1 -1
  211. package/dist/esm/ion-route_4.entry.js +2 -2
  212. package/dist/esm/ion-searchbar.entry.js +4 -4
  213. package/dist/esm/ion-segment-content.entry.js +1 -1
  214. package/dist/esm/ion-segment-view.entry.js +2 -2
  215. package/dist/esm/ion-segment_2.entry.js +4 -4
  216. package/dist/esm/ion-select-modal.entry.js +1 -1
  217. package/dist/esm/ion-select_3.entry.js +40 -58
  218. package/dist/esm/ion-spinner.entry.js +1 -1
  219. package/dist/esm/ion-split-pane.entry.js +2 -2
  220. package/dist/esm/ion-tab-bar_2.entry.js +4 -4
  221. package/dist/esm/ion-tab_2.entry.js +3 -3
  222. package/dist/esm/ion-text.entry.js +2 -2
  223. package/dist/esm/ion-textarea.entry.js +43 -54
  224. package/dist/esm/ion-toast.entry.js +2 -2
  225. package/dist/esm/ion-toggle.entry.js +4 -4
  226. package/dist/esm/slot-mutation-controller-u741eD3Z.js +393 -0
  227. package/dist/ionic/ionic.esm.js +1 -1
  228. package/dist/ionic/{p-dbfd2d52.entry.js → p-06533d51.entry.js} +1 -1
  229. package/dist/ionic/{p-a641d428.entry.js → p-141f5b47.entry.js} +1 -1
  230. package/dist/ionic/p-14a5e8f5.entry.js +4 -0
  231. package/dist/ionic/{p-12589d59.entry.js → p-19269e04.entry.js} +1 -1
  232. package/dist/ionic/{p-efef6788.entry.js → p-19abbc33.entry.js} +1 -1
  233. package/dist/ionic/{p-5394e1d4.entry.js → p-4204184c.entry.js} +1 -1
  234. package/dist/ionic/p-4bc3ecdb.entry.js +4 -0
  235. package/dist/ionic/{p-21a7fb2a.entry.js → p-4eed9ca1.entry.js} +1 -1
  236. package/dist/ionic/p-5521dc1f.entry.js +4 -0
  237. package/dist/ionic/p-5c3626de.entry.js +4 -0
  238. package/dist/ionic/{p-374b10cb.entry.js → p-5d3b411c.entry.js} +1 -1
  239. package/dist/ionic/p-60576951.entry.js +4 -0
  240. package/dist/ionic/{p-1d2e53e8.entry.js → p-711a8319.entry.js} +1 -1
  241. package/dist/ionic/{p-48b6835f.entry.js → p-71419a55.entry.js} +1 -1
  242. package/dist/ionic/{p-ba8a598f.entry.js → p-79325ffe.entry.js} +1 -1
  243. package/dist/ionic/p-84a38904.entry.js +4 -0
  244. package/dist/ionic/{p-bf7c1f05.entry.js → p-8f204f1e.entry.js} +1 -1
  245. package/dist/ionic/p-9055e897.entry.js +4 -0
  246. package/dist/ionic/{p-6277efba.entry.js → p-9658e083.entry.js} +1 -1
  247. package/dist/ionic/{p-74f30659.entry.js → p-988baee1.entry.js} +1 -1
  248. package/dist/ionic/p-DAztxQR0.js +4 -0
  249. package/dist/ionic/p-DkUB-ROc.js +4 -0
  250. package/dist/ionic/{p-3835a020.entry.js → p-a71232d6.entry.js} +1 -1
  251. package/dist/ionic/{p-08f1ed1c.entry.js → p-a73d8742.entry.js} +1 -1
  252. package/dist/ionic/{p-8a21bdbd.entry.js → p-a8421d18.entry.js} +1 -1
  253. package/dist/ionic/{p-2ce59395.entry.js → p-a8c2c343.entry.js} +1 -1
  254. package/dist/ionic/{p-c3f65965.entry.js → p-bc2bad5f.entry.js} +1 -1
  255. package/dist/ionic/{p-f622796d.entry.js → p-be08d500.entry.js} +1 -1
  256. package/dist/ionic/p-be9a4f51.entry.js +4 -0
  257. package/dist/ionic/{p-33829e94.entry.js → p-ccc5044d.entry.js} +1 -1
  258. package/dist/ionic/{p-3c5fdd27.entry.js → p-ce32912b.entry.js} +1 -1
  259. package/dist/ionic/p-ded69ceb.entry.js +4 -0
  260. package/dist/ionic/{p-cec87704.entry.js → p-e0c6e31e.entry.js} +1 -1
  261. package/dist/ionic/{p-09b47b7d.entry.js → p-e8c3e08a.entry.js} +1 -1
  262. package/dist/ionic/{p-8f3a1995.entry.js → p-ed5d540d.entry.js} +1 -1
  263. package/dist/ionic/{p-6b286c5c.entry.js → p-f2802440.entry.js} +1 -1
  264. package/dist/ionic/{p-62e71297.entry.js → p-fe1bfbcf.entry.js} +1 -1
  265. package/dist/types/components/input/input.d.ts +11 -5
  266. package/dist/types/components/select/select.d.ts +12 -6
  267. package/dist/types/components/textarea/textarea.d.ts +12 -5
  268. package/dist/types/utils/forms/index.d.ts +1 -0
  269. package/dist/types/utils/forms/start-container-controller.d.ts +34 -0
  270. package/hydrate/index.js +350 -267
  271. package/hydrate/index.mjs +350 -267
  272. package/package.json +4 -4
  273. package/components/p-DIgGHN7D.js +0 -4
  274. package/components/p-MCJ7HjWe.js +0 -4
  275. package/dist/cjs/input.utils-CP4fzrqk.js +0 -149
  276. package/dist/cjs/notch-controller-BEUpEgb5.js +0 -155
  277. package/dist/esm/input.utils-J6HWocLA.js +0 -146
  278. package/dist/esm/notch-controller-CrUGyHYz.js +0 -153
  279. package/dist/ionic/p-0266b7e1.entry.js +0 -4
  280. package/dist/ionic/p-214e000a.entry.js +0 -4
  281. package/dist/ionic/p-91c6faf1.entry.js +0 -4
  282. package/dist/ionic/p-9b865fe6.entry.js +0 -4
  283. package/dist/ionic/p-BnMQxWON.js +0 -4
  284. package/dist/ionic/p-ac6ef997.entry.js +0 -4
  285. package/dist/ionic/p-b24dc0a1.entry.js +0 -4
  286. package/dist/ionic/p-c8fbe544.entry.js +0 -4
  287. package/dist/ionic/p-cb12f6c3.entry.js +0 -4
  288. package/dist/ionic/p-ede019ef.entry.js +0 -4
  289. package/dist/ionic/p-kJA95YWg.js +0 -4
@@ -112,20 +112,6 @@
112
112
  box-sizing: border-box;
113
113
  }
114
114
 
115
- /**
116
- * Since the label sits on top of the element,
117
- * the component needs to be taller otherwise the
118
- * label will appear too close to the textarea text.
119
- * Also, floating and stacked labels should not
120
- * push the label down since it it
121
- * sits on top of the textarea.
122
- */
123
- :host(.textarea-label-placement-floating),
124
- :host(.textarea-label-placement-stacked) {
125
- --padding-top: 0px;
126
- min-height: 56px;
127
- }
128
-
129
115
  /**
130
116
  * When the cols property is set we should
131
117
  * respect that width instead of defaulting
@@ -248,8 +234,8 @@
248
234
  padding-inline-start: var(--padding-start);
249
235
  -webkit-padding-end: var(--padding-end);
250
236
  padding-inline-end: var(--padding-end);
251
- padding-top: 0px;
252
- padding-bottom: 0px;
237
+ padding-top: 0;
238
+ padding-bottom: 0;
253
239
  border-radius: var(--border-radius);
254
240
  display: flex;
255
241
  position: relative;
@@ -262,23 +248,46 @@
262
248
  line-height: normal;
263
249
  }
264
250
 
251
+ .textarea-control {
252
+ padding-left: 0;
253
+ padding-right: 0;
254
+ padding-top: var(--padding-top);
255
+ padding-bottom: var(--padding-bottom);
256
+ display: flex;
257
+ flex-grow: 1;
258
+ align-items: start;
259
+ align-self: stretch;
260
+ width: 100%;
261
+ /**
262
+ * Allows the control to shrink below the label and textarea's intrinsic
263
+ * width, preventing the start and end slots from being pushed outside
264
+ * the wrapper. The label and textarea truncate independently, so it can
265
+ * use whatever space remains after accounting for the slots.
266
+ */
267
+ min-width: 0;
268
+ }
269
+
265
270
  .native-wrapper {
266
271
  position: relative;
267
272
  width: 100%;
268
273
  height: 100%;
269
274
  }
270
275
 
271
- :host(.has-focus) textarea {
272
- caret-color: var(--highlight-color);
276
+ /**
277
+ * When the label sits beside the textarea, the label should size to its content
278
+ * and the textarea should take the remaining space. A zero flex basis prevents
279
+ * the textarea from requesting its full width and forcing the label to shrink.
280
+ * Stacked and floating placements use a column layout, so their flex basis
281
+ * controls height instead and does not need to be overridden.
282
+ */
283
+ :host(.textarea-label-placement-start) .native-wrapper,
284
+ :host(.textarea-label-placement-end) .native-wrapper,
285
+ :host(.textarea-label-placement-fixed) .native-wrapper {
286
+ flex: 1 1 0;
273
287
  }
274
288
 
275
- .native-wrapper textarea {
276
- -webkit-padding-start: 0px;
277
- padding-inline-start: 0px;
278
- -webkit-padding-end: 0px;
279
- padding-inline-end: 0px;
280
- padding-top: var(--padding-top);
281
- padding-bottom: var(--padding-bottom);
289
+ :host(.has-focus) textarea {
290
+ caret-color: var(--highlight-color);
282
291
  }
283
292
 
284
293
  .native-wrapper {
@@ -305,8 +314,8 @@
305
314
  .native-wrapper::after {
306
315
  padding-left: 0;
307
316
  padding-right: 0;
308
- padding-top: var(--padding-top);
309
- padding-bottom: var(--padding-bottom);
317
+ padding-top: 0;
318
+ padding-bottom: 0;
310
319
  margin-left: 0;
311
320
  margin-right: 0;
312
321
  margin-top: 0;
@@ -332,12 +341,6 @@
332
341
  word-break: break-word;
333
342
  }
334
343
 
335
- .textarea-wrapper-inner {
336
- display: flex;
337
- width: 100%;
338
- min-height: inherit;
339
- }
340
-
341
344
  :host(.ion-touched.ion-invalid) {
342
345
  --highlight-color: var(--highlight-color-invalid);
343
346
  }
@@ -421,12 +424,12 @@
421
424
  }
422
425
 
423
426
  .label-text-wrapper {
424
- -webkit-padding-start: 0px;
425
- padding-inline-start: 0px;
426
- -webkit-padding-end: 0px;
427
- padding-inline-end: 0px;
428
- padding-top: var(--padding-top);
429
- padding-bottom: var(--padding-bottom);
427
+ /**
428
+ * Allows the label to shrink below its intrinsic content width.
429
+ * Without this the label keeps its full width and can push the
430
+ * textarea and end slot outside the wrapper.
431
+ */
432
+ min-width: 0;
430
433
  /**
431
434
  * Label text should not extend
432
435
  * beyond the bounds of the textarea.
@@ -445,6 +448,18 @@
445
448
  pointer-events: none;
446
449
  }
447
450
 
451
+ /**
452
+ * When start/end slots are added or removed, we temporarily
453
+ * disable the label transition to prevent the floating label
454
+ * from animating as its position is adjusted.
455
+ *
456
+ * This class is applied by the start container controller, so
457
+ * renaming it here requires renaming it there too.
458
+ */
459
+ :host(.skip-label-transition) .label-text-wrapper {
460
+ transition: none;
461
+ }
462
+
448
463
  /**
449
464
  * We need to use two elements instead of
450
465
  * one. The .label-text-wrapper is responsible
@@ -488,7 +503,7 @@
488
503
  * Label is on the left of the textarea in LTR and
489
504
  * on the right in RTL.
490
505
  */
491
- :host(.textarea-label-placement-start) .textarea-wrapper {
506
+ :host(.textarea-label-placement-start) .textarea-control {
492
507
  flex-direction: row;
493
508
  }
494
509
 
@@ -510,7 +525,7 @@
510
525
  * Label is on the right of the textarea in LTR and
511
526
  * on the left in RTL.
512
527
  */
513
- :host(.textarea-label-placement-end) .textarea-wrapper {
528
+ :host(.textarea-label-placement-end) .textarea-control {
514
529
  flex-direction: row-reverse;
515
530
  }
516
531
 
@@ -560,8 +575,15 @@
560
575
  * down when the textarea is focused or has a value.
561
576
  *
562
577
  */
563
- :host(.textarea-label-placement-stacked) .textarea-wrapper,
564
- :host(.textarea-label-placement-floating) .textarea-wrapper {
578
+ :host(.textarea-label-placement-stacked),
579
+ :host(.textarea-label-placement-floating) {
580
+ --padding-top: 20px;
581
+ --padding-bottom: 6px;
582
+ }
583
+
584
+ :host(.textarea-label-placement-stacked) .textarea-control,
585
+ :host(.textarea-label-placement-floating) .textarea-control {
586
+ padding-top: 0;
565
587
  flex-direction: column;
566
588
  align-items: start;
567
589
  }
@@ -574,12 +596,10 @@
574
596
  :host(.textarea-label-placement-stacked) .label-text-wrapper,
575
597
  :host(.textarea-label-placement-floating) .label-text-wrapper {
576
598
  transform-origin: left top;
577
- -webkit-padding-start: 0px;
578
- padding-inline-start: 0px;
579
- -webkit-padding-end: 0px;
580
- padding-inline-end: 0px;
581
- padding-top: 0px;
582
- padding-bottom: 0px;
599
+ padding-left: 0;
600
+ padding-right: 0;
601
+ padding-top: 0;
602
+ padding-bottom: 0;
583
603
  max-width: 100%;
584
604
  /**
585
605
  * The 2 ensures the label
@@ -614,13 +634,6 @@
614
634
  margin-bottom: 0px;
615
635
  }
616
636
 
617
- :host(.textarea-label-placement-stacked) ::slotted([slot=start]),
618
- :host(.textarea-label-placement-stacked) ::slotted([slot=end]),
619
- :host(.textarea-label-placement-floating) ::slotted([slot=start]),
620
- :host(.textarea-label-placement-floating) ::slotted([slot=end]) {
621
- margin-top: 8px;
622
- }
623
-
624
637
  /**
625
638
  * This makes the label sit over the textarea
626
639
  * when the textarea is blurred and has no value.
@@ -655,19 +668,17 @@
655
668
  max-width: calc(100% / 0.75);
656
669
  }
657
670
 
658
- .start-slot-wrapper, .end-slot-wrapper {
659
- padding-left: 0;
660
- padding-right: 0;
661
- padding-top: var(--padding-top);
662
- padding-bottom: var(--padding-bottom);
671
+ .textarea-start,
672
+ .textarea-end {
663
673
  display: flex;
674
+ position: relative;
664
675
  flex-shrink: 0;
665
676
  align-self: start;
666
677
  }
667
678
 
668
679
  ::slotted([slot=start]),
669
680
  ::slotted([slot=end]) {
670
- margin-top: 0;
681
+ margin-top: var(--padding-top);
671
682
  }
672
683
 
673
684
  ::slotted([slot=start]:last-of-type) {
@@ -906,7 +917,6 @@
906
917
  --border-radius: 4px;
907
918
  --padding-start: 16px;
908
919
  --padding-end: 16px;
909
- min-height: 56px;
910
920
  }
911
921
 
912
922
  /**
@@ -1034,7 +1044,14 @@
1034
1044
  --border-radius: 4px;
1035
1045
  --padding-start: 16px;
1036
1046
  --padding-end: 16px;
1037
- min-height: 56px;
1047
+ /**
1048
+ * The measured width of the start container, as a negative offset
1049
+ * in LTR and a positive one in RTL. Written to the host by the
1050
+ * start container controller, so renaming it here requires renaming
1051
+ * it there too. Declared with a default so the label is positioned
1052
+ * correctly before the first measurement runs.
1053
+ */
1054
+ --internal-start-container-adjustment: 0px;
1038
1055
  }
1039
1056
 
1040
1057
  :host(.textarea-fill-outline.textarea-shape-round) {
@@ -1088,15 +1105,25 @@
1088
1105
  border-bottom: none;
1089
1106
  }
1090
1107
 
1108
+ /**
1109
+ * The resting label is positioned relative to the control so it can size to
1110
+ * the space between the start and end slots. When floating, the label needs
1111
+ * to escape the control and position itself relative to the wrapper instead.
1112
+ */
1113
+ :host(.textarea-fill-outline:not(.label-floating)) .textarea-control {
1114
+ position: relative;
1115
+ }
1116
+
1091
1117
  :host(.textarea-fill-outline.textarea-label-placement-stacked) .label-text-wrapper,
1092
1118
  :host(.textarea-fill-outline.textarea-label-placement-floating) .label-text-wrapper {
1093
1119
  transform-origin: left top;
1094
1120
  position: absolute;
1095
1121
  /**
1096
- * Label text should not extend
1097
- * beyond the bounds of the textarea.
1122
+ * While resting this is the width of the textarea, which already
1123
+ * excludes the start and end slots. Once the label floats the
1124
+ * containing block becomes the wrapper and the rule below takes over.
1098
1125
  */
1099
- max-width: calc(100% - var(--padding-start) - var(--padding-end));
1126
+ max-width: 100%;
1100
1127
  }
1101
1128
  :host-context([dir=rtl]):host(.textarea-fill-outline.textarea-label-placement-stacked) .label-text-wrapper, :host-context([dir=rtl]).textarea-fill-outline.textarea-label-placement-stacked .label-text-wrapper, :host-context([dir=rtl]):host(.textarea-fill-outline.textarea-label-placement-floating) .label-text-wrapper, :host-context([dir=rtl]).textarea-fill-outline.textarea-label-placement-floating .label-text-wrapper {
1102
1129
  transform-origin: right top;
@@ -1121,7 +1148,7 @@
1121
1148
  * This makes the label sit above the textarea.
1122
1149
  */
1123
1150
  :host(.label-floating.textarea-fill-outline) .label-text-wrapper {
1124
- transform: translateY(-32%) scale(0.75);
1151
+ transform: translate(var(--internal-start-container-adjustment, 0px), -32%) scale(0.75);
1125
1152
  margin-left: 0;
1126
1153
  margin-right: 0;
1127
1154
  margin-top: 0;
@@ -1137,7 +1164,7 @@
1137
1164
 
1138
1165
  /**
1139
1166
  * This ensures that the textarea does not
1140
- * overlap the floating label while still
1167
+ * overlap the outline container while still
1141
1168
  * remaining visually centered.
1142
1169
  */
1143
1170
  :host(.textarea-fill-outline.textarea-label-placement-stacked) textarea,
@@ -1148,17 +1175,10 @@
1148
1175
  margin-inline-start: 0px;
1149
1176
  -webkit-margin-end: 0px;
1150
1177
  margin-inline-end: 0px;
1151
- margin-top: 12px;
1178
+ margin-top: 19px;
1152
1179
  margin-bottom: 0px;
1153
1180
  }
1154
1181
 
1155
- :host(.textarea-fill-outline.textarea-label-placement-stacked) ::slotted([slot=start]),
1156
- :host(.textarea-fill-outline.textarea-label-placement-stacked) ::slotted([slot=end]),
1157
- :host(.textarea-fill-outline.textarea-label-placement-floating) ::slotted([slot=start]),
1158
- :host(.textarea-fill-outline.textarea-label-placement-floating) ::slotted([slot=end]) {
1159
- margin-top: 12px;
1160
- }
1161
-
1162
1182
  :host(.textarea-fill-outline) .textarea-outline-container {
1163
1183
  left: 0;
1164
1184
  right: 0;
@@ -1276,6 +1296,7 @@
1276
1296
  --padding-bottom: 8px;
1277
1297
  --padding-start: 0px;
1278
1298
  --highlight-height: 2px;
1299
+ min-height: 72px;
1279
1300
  font-size: inherit;
1280
1301
  }
1281
1302
 
@@ -1337,6 +1358,11 @@
1337
1358
  --border-radius: 16px;
1338
1359
  }
1339
1360
 
1361
+ ::slotted(ion-button[slot=start]),
1362
+ ::slotted(ion-button[slot=end]) {
1363
+ margin-top: 7px;
1364
+ }
1365
+
1340
1366
  /**
1341
1367
  * Slotted buttons have a lot of default padding that can
1342
1368
  * cause them to look misaligned from other pieces such
@@ -5,7 +5,7 @@ import { Host, h } from "@stencil/core";
5
5
  import { getIonMode } from "../../global/ionic-global";
6
6
  export class Thumbnail {
7
7
  render() {
8
- return (h(Host, { key: '833e947c683b482a78f8f0df8c9a68e99478bbaa', class: getIonMode(this) }, h("slot", { key: '6d1e9e686db88d91379f14121058dbf035d8ded2' })));
8
+ return (h(Host, { key: 'ff9d2a4886b1c90a316c761f1160111f0e997f5d', class: getIonMode(this) }, h("slot", { key: '9a0f0d69e3713831e88c8770a60b28ff1a03abb6' })));
9
9
  }
10
10
  static get is() { return "ion-thumbnail"; }
11
11
  static get encapsulation() { return "shadow"; }
@@ -39,11 +39,11 @@ export class ToolbarTitle {
39
39
  render() {
40
40
  const mode = getIonMode(this);
41
41
  const size = this.getSize();
42
- return (h(Host, { key: 'd9317e8e66cb6112717f5a9c252658777efbd873', class: createColorClasses(this.color, {
42
+ return (h(Host, { key: 'c5f0b913ff0a22d9bf02da48a313a613c2ac8fe7', class: createColorClasses(this.color, {
43
43
  [mode]: true,
44
44
  [`title-${size}`]: true,
45
45
  'title-rtl': document.dir === 'rtl',
46
- }) }, h("div", { key: 'a4d011d6d409bf006d8efe33667002edb109820a', class: "toolbar-title" }, h("slot", { key: '4ca3303b957a0e5387f1e9058e5adb4c6275afcc' }))));
46
+ }) }, h("div", { key: '5253b9e39fb764bfe1e57370719139f8a83e9904', class: "toolbar-title" }, h("slot", { key: 'e38b1eccb0175c36f8cab211aee7ce4d61fc9035' }))));
47
47
  }
48
48
  static get is() { return "ion-title"; }
49
49
  static get encapsulation() { return "shadow"; }
@@ -529,14 +529,14 @@ export class Toast {
529
529
  if (layout === 'stacked' && startButtons.length > 0 && endButtons.length > 0) {
530
530
  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);
531
531
  }
532
- return (h(Host, { key: '2acb2cd2e12ea0082986495929e4a596d4da2f38', tabindex: "-1", ...this.htmlAttributes, style: {
532
+ return (h(Host, { key: '15d2ff8b689e40bb5cae3e304448dadf91b11b88', tabindex: "-1", ...this.htmlAttributes, style: {
533
533
  zIndex: `${60000 + this.overlayIndex}`,
534
534
  }, class: createColorClasses(this.color, {
535
535
  [mode]: true,
536
536
  ...getClassMap(this.cssClass),
537
537
  'overlay-hidden': true,
538
538
  'toast-translucent': this.translucent,
539
- }), onIonToastWillDismiss: this.dispatchCancelHandler }, h("div", { key: '8b24ba5d3d51d1ab94b9bf6bb5d6e4b8bb3248a7', class: wrapperClass, part: "wrapper" }, h("div", { key: 'e1ebdf4f0425cc7b1e2688667ee9a2b3c545804a', class: "toast-container", part: "container" }, this.renderButtons(startButtons, 'start'), this.icon !== undefined && (h("ion-icon", { key: '552b1ab8f4e72882cc8e878579c7a594119677e1', class: "toast-icon", part: "icon", icon: this.icon, lazy: false, "aria-hidden": "true" })), h("div", { key: '8ac8d64f632fbedadb180132c83043474466bee0', class: "toast-content", part: "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')))));
539
+ }), onIonToastWillDismiss: this.dispatchCancelHandler }, h("div", { key: 'd26cc17a59e3d81810e22ee422398f2cc4c7a05c', class: wrapperClass, part: "wrapper" }, h("div", { key: 'f15e1a97f13defcbf96612df4c7ba45999e6244d', class: "toast-container", part: "container" }, this.renderButtons(startButtons, 'start'), this.icon !== undefined && (h("ion-icon", { key: '639cacec828f969673071e54dc68284050e9f2fd', class: "toast-icon", part: "icon", icon: this.icon, lazy: false, "aria-hidden": "true" })), h("div", { key: 'a07e68cf68e4c507e4515de1a4b43dd8fb3541d3', class: "toast-content", part: "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')))));
540
540
  }
541
541
  static get is() { return "ion-toast"; }
542
542
  static get encapsulation() { return "shadow"; }
@@ -353,7 +353,7 @@ export class Toggle {
353
353
  // The attributes are matched too because the class needs the item to render.
354
354
  const inClickableItem = hostContext('ion-item.ion-activatable, ion-item[button], ion-item[href]', el);
355
355
  renderHiddenInput(true, el, name, checked ? value : '', disabled);
356
- return (h(Host, { key: 'ec5ce11209c70083c0b2ef1ea54de3033cfa7e89', 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, {
356
+ return (h(Host, { key: '148d15040257b05b3769da5a2439d051e357cbba', 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, {
357
357
  [mode]: true,
358
358
  'in-item': inItem,
359
359
  // `ion-focusable` has to stay on because it is what makes the item focusable.
@@ -367,10 +367,10 @@ export class Toggle {
367
367
  [`toggle-alignment-${alignment}`]: alignment !== undefined,
368
368
  [`toggle-label-placement-${labelPlacement}`]: true,
369
369
  [`toggle-${rtl}`]: true,
370
- }) }, h("label", { key: '95c1c7abd546ed2703d493acb967cf93e056a376', class: "toggle-wrapper", htmlFor: inputId }, h("input", { key: '7a206f525a4d340d94c668d6fc3b1f585cd97683', type: "checkbox", role: "switch", "aria-checked": `${checked}`, checked: checked, disabled: disabled, id: inputId, required: required, ...inheritedAttributes }), h("div", { key: '62c2a365f980d46c2d7eaf1cbd19498d5813e1b1', class: {
370
+ }) }, h("label", { key: '0dbc40adc87e2ab4bdcd9a9fef43393484174c18', class: "toggle-wrapper", htmlFor: inputId }, h("input", { key: '92dee565687fc9a883f97091ead1bbb51df43779', type: "checkbox", role: "switch", "aria-checked": `${checked}`, checked: checked, disabled: disabled, id: inputId, required: required, ...inheritedAttributes }), h("div", { key: 'f057bc57714b26e84226ee931e09212b86dba69f', class: {
371
371
  'label-text-wrapper': true,
372
372
  'label-text-wrapper-hidden': !hasLabel,
373
- }, part: "label", id: inputLabelId, onClick: this.onDivLabelClick }, h("slot", { key: 'f352f834790e1e9581ecb107f9a8aaaeb101fae5' }), this.renderHintText()), h("div", { key: 'f086ba9e31e9842ec438bb3226927faf9d0a7ea9', class: "native-wrapper" }, this.renderToggleControl()))));
373
+ }, part: "label", id: inputLabelId, onClick: this.onDivLabelClick }, h("slot", { key: '345efb5ce20f8124d1e74877b4943edf82fe2f8e' }), this.renderHintText()), h("div", { key: 'fc1a7fb6b65064307fbe0a50178559a52d6aedb7', class: "native-wrapper" }, this.renderToggleControl()))));
374
374
  }
375
375
  static get is() { return "ion-toggle"; }
376
376
  static get encapsulation() { return "shadow"; }
@@ -70,13 +70,13 @@ export class Toolbar {
70
70
  this.childrenStyles.forEach((value) => {
71
71
  Object.assign(childStyles, value);
72
72
  });
73
- return (h(Host, { key: '40bad6fa7e94262438da4bbe037dcf8a5fa2df22', class: {
73
+ return (h(Host, { key: 'c16803dc4eae9972ef19bf43aa74b94feb4fd4c1', class: {
74
74
  ...childStyles,
75
75
  ...createColorClasses(this.color, {
76
76
  [mode]: true,
77
77
  'in-toolbar': hostContext('ion-toolbar', this.el),
78
78
  }),
79
- } }, h("div", { key: 'df44c9f0fe3958116ab860b0dad79c53b89f6c59', class: "toolbar-background", part: "background" }), h("div", { key: '2169ffa576875b8d5624211cc0b4bf86191562bc', class: "toolbar-container", part: "container" }, h("slot", { key: 'c8910dcf1ce98ab427fd89c3396a67c2a75bdd07', name: "start" }), h("slot", { key: '05da24d5ef96b9eebd83b534ce02c1f7bcd06680', name: "secondary" }), h("div", { key: '090fea1541e7e2b6ad74a6ded4eadffdb471ccce', class: "toolbar-content", part: "content" }, h("slot", { key: '507e143f92f6fa59ff23d94026411fa2c74f2f8e' })), h("slot", { key: 'f79fdee472e657e26a910cb89d7551943e40e440', name: "primary" }), h("slot", { key: 'dd40fe9ed490cf4346c642e195fdb524dc6cc4f5', name: "end" }))));
79
+ } }, h("div", { key: '20e3f85844c94b8399c245d2df125e6ab678d681', class: "toolbar-background", part: "background" }), h("div", { key: '12f09e324e8d9130b9d30c493106b500233fb016', class: "toolbar-container", part: "container" }, h("slot", { key: '6da0fe99ee0c4d7c969712e2908a4e7e6be5ed2c', name: "start" }), h("slot", { key: '177c346d6dcabb7857d810cda7d25c6dde32e6e2', name: "secondary" }), h("div", { key: '8c921b415940c71bf4c1a2c5c6887f36ad1afd16', class: "toolbar-content", part: "content" }, h("slot", { key: '1f2976b80d967bd51e86ed1357b363271d655df2' })), h("slot", { key: '0f7618044a7e8b0d9b715a8e208070f7ef2ee4c8', name: "primary" }), h("slot", { key: '125c393197e0660a3c2638dd4628c41ef7e05f19', name: "end" }))));
80
80
  }
81
81
  static get is() { return "ion-toolbar"; }
82
82
  static get encapsulation() { return "shadow"; }
@@ -2,6 +2,7 @@
2
2
  * (C) Ionic http://ionicframework.com - MIT License
3
3
  */
4
4
  export * from './notch-controller';
5
+ export * from './start-container-controller';
5
6
  export * from './compare-with-utils';
6
7
  export * from './item-multiple-inputs';
7
8
  export * from './validity';
@@ -0,0 +1,132 @@
1
+ /*!
2
+ * (C) Ionic http://ionicframework.com - MIT License
3
+ */
4
+ import { raf } from "../helpers";
5
+ import { isRTL } from "../rtl/index";
6
+ /**
7
+ * Applied to the host while the label is being repositioned. The
8
+ * component stylesheets style this class, so it must stay in sync with
9
+ * the `skip-label-transition` selector in those files. Renaming it here
10
+ * requires renaming it there too.
11
+ */
12
+ export const SKIP_LABEL_TRANSITION_CLASS = 'skip-label-transition';
13
+ /**
14
+ * Set on the host as an inline style. The component stylesheets declare
15
+ * this property and read it with `var()`, so it must stay in sync with
16
+ * the `--internal-start-container-adjustment` references in those files.
17
+ * Renaming it here requires renaming it there too.
18
+ */
19
+ export const START_CONTAINER_ADJUSTMENT_VAR = '--internal-start-container-adjustment';
20
+ /**
21
+ * A utility to measure and update the start container width adjustment
22
+ * for form components (input, textarea, select) with `fill="outline"`.
23
+ * This adjustment compensates for the start container width when
24
+ * positioning floating/stacked labels within the outline border.
25
+ *
26
+ * Measurement is deferred with raf() to avoid forcing layout during
27
+ * component updates, and a ResizeObserver watches for dynamic width
28
+ * changes (e.g., when web fonts load or async content changes).
29
+ *
30
+ * @internal
31
+ * @param el - The host element (ion-input, ion-textarea, or ion-select).
32
+ * @param getStartContainer - A callback that returns the start container element.
33
+ * @param shouldApplyAdjustment - A callback that determines whether the adjustment should be applied.
34
+ */
35
+ export const createStartContainerController = (el, getStartContainer, shouldApplyAdjustment) => {
36
+ let resizeObserver;
37
+ let observedContainer;
38
+ let measurementRaf;
39
+ let transitionRaf;
40
+ let appliedAdjustment;
41
+ const calculateAdjustment = () => {
42
+ const startSlot = getStartContainer();
43
+ if (!startSlot || !shouldApplyAdjustment()) {
44
+ return '';
45
+ }
46
+ /*
47
+ * Round to one decimal place so fractional widths produce a stable
48
+ * label offset when the start container is added, removed, or resized.
49
+ */
50
+ const startContainerWidth = startSlot.getBoundingClientRect().width;
51
+ const roundedWidth = Math.round(startContainerWidth * 10) / 10;
52
+ const sign = isRTL(el) ? '' : '-';
53
+ return roundedWidth ? `${sign}${roundedWidth}px` : '0px';
54
+ };
55
+ const scheduleAdjustmentUpdate = () => {
56
+ // Return if there is already a measurement queued to avoid a flicker
57
+ if (measurementRaf !== undefined) {
58
+ return;
59
+ }
60
+ /*
61
+ * Defer the measurement until the next animation frame so layout
62
+ * is measured after the current update has been applied.
63
+ */
64
+ measurementRaf = raf(() => {
65
+ measurementRaf = undefined;
66
+ const adjustment = calculateAdjustment();
67
+ // Only suppress the label transition when the label has to move
68
+ if (adjustment !== appliedAdjustment) {
69
+ // Discard a removal queued by an earlier change
70
+ if (transitionRaf !== undefined) {
71
+ cancelAnimationFrame(transitionRaf);
72
+ }
73
+ el.classList.add(SKIP_LABEL_TRANSITION_CLASS);
74
+ el.style.setProperty(START_CONTAINER_ADJUSTMENT_VAR, adjustment);
75
+ appliedAdjustment = adjustment;
76
+ // Re-enable the transition once the new offset has been painted
77
+ transitionRaf = raf(() => {
78
+ transitionRaf = undefined;
79
+ el.classList.remove(SKIP_LABEL_TRANSITION_CLASS);
80
+ });
81
+ }
82
+ setupResizeObserver();
83
+ });
84
+ };
85
+ const disconnectResizeObserver = () => {
86
+ if (resizeObserver) {
87
+ resizeObserver.disconnect();
88
+ resizeObserver = undefined;
89
+ observedContainer = undefined;
90
+ }
91
+ };
92
+ const setupResizeObserver = () => {
93
+ const startSlot = getStartContainer();
94
+ // Stop watching once the adjustment no longer applies
95
+ if (!startSlot || !shouldApplyAdjustment()) {
96
+ disconnectResizeObserver();
97
+ return;
98
+ }
99
+ // Return when prerendering or already watching this container
100
+ if (typeof ResizeObserver !== 'function' || (resizeObserver && observedContainer === startSlot)) {
101
+ return;
102
+ }
103
+ disconnectResizeObserver();
104
+ resizeObserver = new ResizeObserver(() => {
105
+ scheduleAdjustmentUpdate();
106
+ });
107
+ observedContainer = startSlot;
108
+ resizeObserver.observe(startSlot);
109
+ };
110
+ const calculateStartContainerWidth = () => {
111
+ scheduleAdjustmentUpdate();
112
+ };
113
+ const destroy = () => {
114
+ disconnectResizeObserver();
115
+ if (measurementRaf !== undefined) {
116
+ cancelAnimationFrame(measurementRaf);
117
+ measurementRaf = undefined;
118
+ }
119
+ // Tearing down mid-toggle would leave the transition disabled
120
+ if (transitionRaf !== undefined) {
121
+ cancelAnimationFrame(transitionRaf);
122
+ transitionRaf = undefined;
123
+ el.classList.remove(SKIP_LABEL_TRANSITION_CLASS);
124
+ }
125
+ // Re-apply from scratch if the element is connected again
126
+ appliedAdjustment = undefined;
127
+ };
128
+ return {
129
+ calculateStartContainerWidth,
130
+ destroy,
131
+ };
132
+ };
package/dist/docs.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2026-08-14T18:01:38",
2
+ "timestamp": "2026-08-14T19:32:20",
3
3
  "compiler": {
4
4
  "name": "@stencil/core",
5
5
  "version": "4.43.5",
@@ -30384,7 +30384,15 @@
30384
30384
  },
30385
30385
  {
30386
30386
  "name": "part",
30387
- "text": "inner - The inner element of the wrapper that manages the slots, selected values or placeholder, and toggle icons."
30387
+ "text": "start - The wrapper element for the content in the start slot."
30388
+ },
30389
+ {
30390
+ "name": "part",
30391
+ "text": "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."
30392
+ },
30393
+ {
30394
+ "name": "part",
30395
+ "text": "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."
30388
30396
  }
30389
30397
  ],
30390
30398
  "usage": {},
@@ -31559,6 +31567,14 @@
31559
31567
  "name": "container",
31560
31568
  "docs": "The container for the selected text or placeholder."
31561
31569
  },
31570
+ {
31571
+ "name": "control",
31572
+ "docs": "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."
31573
+ },
31574
+ {
31575
+ "name": "end",
31576
+ "docs": "The wrapper element for the content in the end slot. When the label is floating or stacked, this part also contains the dropdown icon."
31577
+ },
31562
31578
  {
31563
31579
  "name": "error-text",
31564
31580
  "docs": "Supporting text displayed beneath the select when the select is invalid and touched."
@@ -31571,10 +31587,6 @@
31571
31587
  "name": "icon",
31572
31588
  "docs": "The select icon container."
31573
31589
  },
31574
- {
31575
- "name": "inner",
31576
- "docs": "The inner element of the wrapper that manages the slots, selected values or placeholder, and toggle icons."
31577
- },
31578
31590
  {
31579
31591
  "name": "label",
31580
31592
  "docs": "The label text describing the select."
@@ -31583,6 +31595,10 @@
31583
31595
  "name": "placeholder",
31584
31596
  "docs": "The text displayed in the select when there is no value."
31585
31597
  },
31598
+ {
31599
+ "name": "start",
31600
+ "docs": "The wrapper element for the content in the start slot."
31601
+ },
31586
31602
  {
31587
31603
  "name": "supporting-text",
31588
31604
  "docs": "Supporting text displayed beneath the select."
@@ -0,0 +1,33 @@
1
+ /*!
2
+ * (C) Ionic http://ionicframework.com - MIT License
3
+ */
4
+ import { j as printIonError } from './index-ChhhtsGZ.js';
5
+
6
+ const getCounterText = (value, maxLength, counterFormatter) => {
7
+ const valueLength = value == null ? 0 : value.toString().length;
8
+ const defaultCounterText = defaultCounterFormatter(valueLength, maxLength);
9
+ /**
10
+ * If developers did not pass a custom formatter,
11
+ * use the default one.
12
+ */
13
+ if (counterFormatter === undefined) {
14
+ return defaultCounterText;
15
+ }
16
+ /**
17
+ * Otherwise, try to use the custom formatter
18
+ * and fallback to the default formatter if
19
+ * there was an error.
20
+ */
21
+ try {
22
+ return counterFormatter(valueLength, maxLength);
23
+ }
24
+ catch (e) {
25
+ printIonError('[ion-input] - Exception in provided `counterFormatter`:', e);
26
+ return defaultCounterText;
27
+ }
28
+ };
29
+ const defaultCounterFormatter = (length, maxlength) => {
30
+ return `${length} / ${maxlength}`;
31
+ };
32
+
33
+ export { getCounterText as g };