@ionic/core 7.5.8-dev.11701791090.18ebbea8 → 7.5.8-dev.11701876182.1e71e7a0

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 (383) hide show
  1. package/components/animation.js +12 -11
  2. package/components/checkbox.js +5 -3
  3. package/components/index4.js +10 -12
  4. package/components/index5.js +0 -22
  5. package/components/input-shims.js +12 -7
  6. package/components/input.utils.js +3 -2
  7. package/components/ion-datetime.js +2 -2
  8. package/components/ion-infinite-scroll.js +11 -3
  9. package/components/ion-input.js +33 -29
  10. package/components/ion-modal.js +2 -2
  11. package/components/ion-range.js +5 -3
  12. package/components/ion-select.js +44 -29
  13. package/components/ion-skeleton-text.js +14 -1
  14. package/components/ion-textarea.js +32 -32
  15. package/components/ion-toast.js +419 -74
  16. package/components/ion-toggle.js +5 -3
  17. package/components/item.js +2 -2
  18. package/components/label.js +2 -2
  19. package/components/overlays.js +2 -1
  20. package/components/radio-group.js +2 -0
  21. package/components/radio.js +45 -5
  22. package/dist/cjs/{animation-cc40e39c.js → animation-9b401d39.js} +13 -12
  23. package/dist/cjs/{button-active-417ccdcb.js → button-active-a5185907.js} +1 -1
  24. package/dist/cjs/{capacitor-46980811.js → capacitor-c04564bf.js} +1 -1
  25. package/dist/cjs/compare-with-utils-df1001d7.js +44 -0
  26. package/dist/cjs/{haptic-216df36c.js → haptic-b882e0bb.js} +1 -1
  27. package/dist/cjs/{index-8c1e77d6.js → index-b4f986cd.js} +1 -1
  28. package/dist/cjs/index-c8d52405.js +10 -0
  29. package/dist/cjs/{index-5cbb20f9.js → index-ce101dc9.js} +11 -13
  30. package/dist/cjs/{index-d4c2e02c.js → index-f8f13389.js} +2 -2
  31. package/dist/cjs/index.cjs.js +8 -8
  32. package/dist/cjs/{input-shims-87102b6a.js → input-shims-a23bb0f4.js} +15 -10
  33. package/dist/cjs/{input.utils-2a11c1fe.js → input.utils-3d0166a2.js} +4 -3
  34. package/dist/cjs/ion-action-sheet.cjs.entry.js +6 -6
  35. package/dist/cjs/ion-alert.cjs.entry.js +6 -6
  36. package/dist/cjs/ion-app_8.cjs.entry.js +8 -8
  37. package/dist/cjs/ion-checkbox.cjs.entry.js +5 -3
  38. package/dist/cjs/ion-datetime_3.cjs.entry.js +7 -7
  39. package/dist/cjs/ion-infinite-scroll_2.cjs.entry.js +11 -3
  40. package/dist/cjs/ion-input.cjs.entry.js +36 -32
  41. package/dist/cjs/ion-item_8.cjs.entry.js +17 -4
  42. package/dist/cjs/ion-loading.cjs.entry.js +3 -3
  43. package/dist/cjs/ion-menu_3.cjs.entry.js +5 -5
  44. package/dist/cjs/ion-modal.cjs.entry.js +8 -8
  45. package/dist/cjs/ion-nav_2.cjs.entry.js +1 -1
  46. package/dist/cjs/ion-picker-column-internal.cjs.entry.js +3 -3
  47. package/dist/cjs/ion-popover.cjs.entry.js +4 -4
  48. package/dist/cjs/ion-radio_2.cjs.entry.js +9 -4
  49. package/dist/cjs/ion-range.cjs.entry.js +5 -3
  50. package/dist/cjs/ion-refresher_2.cjs.entry.js +4 -4
  51. package/dist/cjs/ion-reorder_2.cjs.entry.js +3 -3
  52. package/dist/cjs/ion-select_3.cjs.entry.js +51 -35
  53. package/dist/cjs/ion-tab-bar_2.cjs.entry.js +4 -4
  54. package/dist/cjs/ion-textarea.cjs.entry.js +35 -35
  55. package/dist/cjs/ion-toast.cjs.entry.js +434 -92
  56. package/dist/cjs/ion-toggle.cjs.entry.js +8 -6
  57. package/dist/cjs/ionic.cjs.js +1 -1
  58. package/dist/cjs/{ios.transition-a4ffb5a2.js → ios.transition-6787b799.js} +3 -3
  59. package/dist/cjs/{keyboard-9390928c.js → keyboard-0272231f.js} +1 -1
  60. package/dist/cjs/{keyboard-7d621ee9.js → keyboard-af1bb365.js} +3 -3
  61. package/dist/cjs/{keyboard-controller-2158b478.js → keyboard-controller-c05e747a.js} +2 -2
  62. package/dist/cjs/loader.cjs.js +1 -1
  63. package/dist/cjs/{md.transition-292abe1c.js → md.transition-e033d20a.js} +3 -3
  64. package/dist/cjs/{notch-controller-1dce508a.js → notch-controller-9735e7ac.js} +1 -1
  65. package/dist/cjs/{overlays-5c379703.js → overlays-27a6fb16.js} +3 -1
  66. package/dist/collection/components/checkbox/checkbox.ios.css +0 -6
  67. package/dist/collection/components/checkbox/checkbox.js +4 -1
  68. package/dist/collection/components/checkbox/checkbox.md.css +0 -6
  69. package/dist/collection/components/checkbox/test/checkbox.spec.js +14 -0
  70. package/dist/collection/components/datetime/datetime.ios.css +1 -0
  71. package/dist/collection/components/datetime/datetime.md.css +1 -0
  72. package/dist/collection/components/infinite-scroll/infinite-scroll.js +11 -3
  73. package/dist/collection/components/infinite-scroll/test/small-dom-update/infinite-scroll.e2e.js +31 -0
  74. package/dist/collection/components/input/input.ios.css +10 -3
  75. package/dist/collection/components/input/input.js +33 -27
  76. package/dist/collection/components/input/input.md.css +13 -12
  77. package/dist/collection/components/input/test/clear-on-edit/input.e2e.js +9 -21
  78. package/dist/collection/components/input/test/slot/input.e2e.js +51 -0
  79. package/dist/collection/components/item/item.ios.css +41 -3
  80. package/dist/collection/components/item/item.md.css +41 -3
  81. package/dist/collection/components/item/test/basic/item.e2e.js +1 -1
  82. package/dist/collection/components/item/test/disabled/item.e2e.js +0 -1
  83. package/dist/collection/components/label/label.ios.css +14 -3
  84. package/dist/collection/components/label/label.md.css +14 -3
  85. package/dist/collection/components/modal/gestures/swipe-to-close.js +2 -1
  86. package/dist/collection/components/note/test/a11y/note.e2e.js +43 -0
  87. package/dist/collection/components/radio/radio.ios.css +0 -6
  88. package/dist/collection/components/radio/radio.js +7 -3
  89. package/dist/collection/components/radio/radio.md.css +0 -6
  90. package/dist/collection/components/radio/test/radio.spec.js +14 -0
  91. package/dist/collection/components/radio-group/radio-group.js +24 -0
  92. package/dist/collection/components/radio-group/test/radio-group.spec.js +69 -0
  93. package/dist/collection/components/range/range.ios.css +0 -6
  94. package/dist/collection/components/range/range.js +4 -1
  95. package/dist/collection/components/range/range.md.css +0 -6
  96. package/dist/collection/components/range/test/range.spec.js +16 -0
  97. package/dist/collection/components/select/select.ios.css +60 -7
  98. package/dist/collection/components/select/select.js +45 -28
  99. package/dist/collection/components/select/select.md.css +63 -19
  100. package/dist/collection/components/select/test/item/select.e2e.js +15 -0
  101. package/dist/collection/components/select/test/label/select.e2e.js +1 -1
  102. package/dist/collection/components/select/test/legacy/wrapping/select.e2e.js +1 -1
  103. package/dist/collection/components/select/test/slot/select.e2e.js +67 -0
  104. package/dist/collection/components/skeleton-text/skeleton-text.js +39 -0
  105. package/dist/collection/components/textarea/test/clear-on-edit/textarea.e2e.js +0 -28
  106. package/dist/collection/components/textarea/test/slot/textarea.e2e.js +51 -0
  107. package/dist/collection/components/textarea/textarea.ios.css +37 -5
  108. package/dist/collection/components/textarea/textarea.js +32 -30
  109. package/dist/collection/components/textarea/textarea.md.css +47 -14
  110. package/dist/collection/components/toast/animations/ios.enter.js +2 -1
  111. package/dist/collection/components/toast/animations/md.enter.js +4 -3
  112. package/dist/collection/components/toast/animations/utils.js +20 -14
  113. package/dist/collection/components/toast/gestures/swipe-to-dismiss.js +267 -0
  114. package/dist/collection/components/toast/test/swipe-gesture/toast.e2e.js +84 -0
  115. package/dist/collection/components/toast/test/toast-config.spec.js +25 -0
  116. package/dist/collection/components/toast/test/toast.spec.js +80 -0
  117. package/dist/collection/components/toast/toast.ios.css +10 -10
  118. package/dist/collection/components/toast/toast.js +104 -1
  119. package/dist/collection/components/toast/toast.md.css +10 -0
  120. package/dist/collection/components/toggle/test/toggle.spec.js +12 -0
  121. package/dist/collection/components/toggle/toggle.ios.css +0 -6
  122. package/dist/collection/components/toggle/toggle.js +4 -1
  123. package/dist/collection/components/toggle/toggle.md.css +0 -6
  124. package/dist/collection/utils/animation/animation.js +12 -11
  125. package/dist/collection/utils/animation/test/animation.spec.js +16 -0
  126. package/dist/collection/utils/browser/index.js +0 -22
  127. package/dist/collection/utils/forms/compare-with-utils.js +39 -0
  128. package/dist/collection/utils/forms/index.js +1 -0
  129. package/dist/collection/utils/input-shims/input-shims.js +12 -6
  130. package/dist/collection/utils/menu-controller/index.js +10 -12
  131. package/dist/collection/utils/overlays.js +1 -0
  132. package/dist/collection/utils/slot-mutation-controller.js +3 -2
  133. package/dist/docs.json +159 -2
  134. package/dist/esm/{animation-fb0e0f6f.js → animation-dde8cc0d.js} +13 -12
  135. package/dist/esm/{button-active-3fdf3e4f.js → button-active-c6ee4f50.js} +1 -1
  136. package/dist/esm/{capacitor-b0e5fe83.js → capacitor-59395cbd.js} +1 -1
  137. package/dist/esm/compare-with-utils-a96ff2ea.js +41 -0
  138. package/dist/esm/{haptic-152c4172.js → haptic-554688a5.js} +1 -1
  139. package/dist/esm/{index-80492ed3.js → index-0c12c22b.js} +11 -13
  140. package/dist/esm/{index-d8817fb0.js → index-1932b201.js} +2 -2
  141. package/dist/esm/{index-ba9976bb.js → index-82eeb47f.js} +1 -1
  142. package/dist/esm/index-a5d50daf.js +7 -0
  143. package/dist/esm/index.js +8 -8
  144. package/dist/esm/{input-shims-0a2e541d.js → input-shims-6539ce13.js} +14 -9
  145. package/dist/esm/{input.utils-2846d430.js → input.utils-a5a2d164.js} +4 -3
  146. package/dist/esm/ion-action-sheet.entry.js +6 -6
  147. package/dist/esm/ion-alert.entry.js +6 -6
  148. package/dist/esm/ion-app_8.entry.js +8 -8
  149. package/dist/esm/ion-checkbox.entry.js +5 -3
  150. package/dist/esm/ion-datetime_3.entry.js +7 -7
  151. package/dist/esm/ion-infinite-scroll_2.entry.js +11 -3
  152. package/dist/esm/ion-input.entry.js +36 -32
  153. package/dist/esm/ion-item_8.entry.js +17 -4
  154. package/dist/esm/ion-loading.entry.js +3 -3
  155. package/dist/esm/ion-menu_3.entry.js +5 -5
  156. package/dist/esm/ion-modal.entry.js +8 -8
  157. package/dist/esm/ion-nav_2.entry.js +1 -1
  158. package/dist/esm/ion-picker-column-internal.entry.js +3 -3
  159. package/dist/esm/ion-popover.entry.js +4 -4
  160. package/dist/esm/ion-radio_2.entry.js +9 -4
  161. package/dist/esm/ion-range.entry.js +5 -3
  162. package/dist/esm/ion-refresher_2.entry.js +4 -4
  163. package/dist/esm/ion-reorder_2.entry.js +3 -3
  164. package/dist/esm/ion-select_3.entry.js +47 -31
  165. package/dist/esm/ion-tab-bar_2.entry.js +4 -4
  166. package/dist/esm/ion-textarea.entry.js +35 -35
  167. package/dist/esm/ion-toast.entry.js +417 -75
  168. package/dist/esm/ion-toggle.entry.js +8 -6
  169. package/dist/esm/ionic.js +1 -1
  170. package/dist/esm/{ios.transition-fd16bec1.js → ios.transition-802a84a6.js} +3 -3
  171. package/dist/esm/{keyboard-c402e885.js → keyboard-52278bd7.js} +3 -3
  172. package/dist/esm/{keyboard-dbb05fb9.js → keyboard-73175e24.js} +1 -1
  173. package/dist/esm/{keyboard-controller-5d90929a.js → keyboard-controller-ec5c2bfa.js} +2 -2
  174. package/dist/esm/loader.js +1 -1
  175. package/dist/esm/{md.transition-94ac93e1.js → md.transition-43c2874d.js} +3 -3
  176. package/dist/esm/{notch-controller-d09b6aca.js → notch-controller-fea7f9c5.js} +1 -1
  177. package/dist/esm/{overlays-abf58489.js → overlays-32ef481d.js} +3 -2
  178. package/dist/esm-es5/{animation-fb0e0f6f.js → animation-dde8cc0d.js} +1 -1
  179. package/dist/esm-es5/{button-active-3fdf3e4f.js → button-active-c6ee4f50.js} +1 -1
  180. package/dist/esm-es5/{capacitor-b0e5fe83.js → capacitor-59395cbd.js} +1 -1
  181. package/dist/esm-es5/compare-with-utils-a96ff2ea.js +4 -0
  182. package/dist/esm-es5/{haptic-152c4172.js → haptic-554688a5.js} +1 -1
  183. package/dist/esm-es5/index-0c12c22b.js +4 -0
  184. package/dist/esm-es5/{index-d8817fb0.js → index-1932b201.js} +1 -1
  185. package/dist/esm-es5/{index-ba9976bb.js → index-82eeb47f.js} +1 -1
  186. package/dist/esm-es5/index.js +1 -1
  187. package/dist/esm-es5/input-shims-6539ce13.js +4 -0
  188. package/dist/esm-es5/input.utils-a5a2d164.js +4 -0
  189. package/dist/esm-es5/ion-action-sheet.entry.js +1 -1
  190. package/dist/esm-es5/ion-alert.entry.js +1 -1
  191. package/dist/esm-es5/ion-app_8.entry.js +1 -1
  192. package/dist/esm-es5/ion-checkbox.entry.js +1 -1
  193. package/dist/esm-es5/ion-datetime_3.entry.js +1 -1
  194. package/dist/esm-es5/ion-infinite-scroll_2.entry.js +1 -1
  195. package/dist/esm-es5/ion-input.entry.js +1 -1
  196. package/dist/esm-es5/ion-item_8.entry.js +1 -1
  197. package/dist/esm-es5/ion-loading.entry.js +1 -1
  198. package/dist/esm-es5/ion-menu_3.entry.js +1 -1
  199. package/dist/esm-es5/ion-modal.entry.js +1 -1
  200. package/dist/esm-es5/ion-nav_2.entry.js +1 -1
  201. package/dist/esm-es5/ion-picker-column-internal.entry.js +1 -1
  202. package/dist/esm-es5/ion-popover.entry.js +1 -1
  203. package/dist/esm-es5/ion-radio_2.entry.js +1 -1
  204. package/dist/esm-es5/ion-range.entry.js +1 -1
  205. package/dist/esm-es5/ion-refresher_2.entry.js +1 -1
  206. package/dist/esm-es5/ion-reorder_2.entry.js +1 -1
  207. package/dist/esm-es5/ion-select_3.entry.js +1 -1
  208. package/dist/esm-es5/ion-tab-bar_2.entry.js +1 -1
  209. package/dist/esm-es5/ion-textarea.entry.js +1 -1
  210. package/dist/esm-es5/ion-toast.entry.js +1 -1
  211. package/dist/esm-es5/ion-toggle.entry.js +1 -1
  212. package/dist/esm-es5/ionic.js +1 -1
  213. package/dist/esm-es5/{ios.transition-fd16bec1.js → ios.transition-802a84a6.js} +1 -1
  214. package/dist/esm-es5/{keyboard-c402e885.js → keyboard-52278bd7.js} +1 -1
  215. package/dist/esm-es5/{keyboard-dbb05fb9.js → keyboard-73175e24.js} +1 -1
  216. package/dist/esm-es5/{keyboard-controller-5d90929a.js → keyboard-controller-ec5c2bfa.js} +1 -1
  217. package/dist/esm-es5/loader.js +1 -1
  218. package/dist/esm-es5/md.transition-43c2874d.js +4 -0
  219. package/dist/esm-es5/{notch-controller-d09b6aca.js → notch-controller-fea7f9c5.js} +1 -1
  220. package/dist/esm-es5/{overlays-abf58489.js → overlays-32ef481d.js} +1 -1
  221. package/dist/html.html-data.json +14 -1
  222. package/dist/ionic/index.esm.js +1 -1
  223. package/dist/ionic/ionic.esm.js +1 -1
  224. package/dist/ionic/p-01d14eba.system.entry.js +4 -0
  225. package/dist/ionic/{p-3de71759.entry.js → p-042e6f4b.entry.js} +1 -1
  226. package/dist/ionic/p-05d83227.system.entry.js +4 -0
  227. package/dist/ionic/{p-32e19bee.system.js → p-0bd51c34.system.js} +1 -1
  228. package/dist/ionic/{p-73637557.system.entry.js → p-16756e94.system.entry.js} +1 -1
  229. package/dist/ionic/p-1b19c04b.entry.js +4 -0
  230. package/dist/ionic/{p-95c26010.system.js → p-1cca10d6.system.js} +1 -1
  231. package/dist/ionic/p-1e4371bd.js +4 -0
  232. package/dist/ionic/{p-0519cd21.entry.js → p-251666e2.entry.js} +1 -1
  233. package/dist/ionic/{p-4e8e09e1.js → p-27281edd.js} +1 -1
  234. package/dist/ionic/p-28249b10.system.entry.js +4 -0
  235. package/dist/ionic/p-28a2c2a2.entry.js +4 -0
  236. package/dist/ionic/p-29d03b3a.js +4 -0
  237. package/dist/ionic/p-2b7827c7.js +4 -0
  238. package/dist/ionic/p-2d3b9fa3.system.entry.js +4 -0
  239. package/dist/ionic/p-2d539df1.entry.js +4 -0
  240. package/dist/ionic/{p-a0126dd5.system.entry.js → p-3137c025.system.entry.js} +1 -1
  241. package/dist/ionic/{p-30029cc2.system.js → p-31fcb233.system.js} +1 -1
  242. package/dist/ionic/{p-b0dc1cf9.system.js → p-33a37fad.system.js} +1 -1
  243. package/dist/ionic/p-36d187af.js +4 -0
  244. package/dist/ionic/p-376a6063.js +4 -0
  245. package/dist/ionic/p-38f2c6bb.system.js +4 -0
  246. package/dist/ionic/{p-2ba0657d.system.entry.js → p-39c31982.system.entry.js} +1 -1
  247. package/dist/ionic/{p-75445583.js → p-3a75d7fd.js} +1 -1
  248. package/dist/ionic/{p-d40a974a.entry.js → p-3dd98a73.entry.js} +1 -1
  249. package/dist/ionic/p-3e6b47e8.system.entry.js +4 -0
  250. package/dist/ionic/p-3f5179b5.entry.js +4 -0
  251. package/dist/ionic/p-40f68333.system.js +4 -0
  252. package/dist/ionic/{p-643a8fae.js → p-42f189f4.js} +1 -1
  253. package/dist/ionic/{p-9c3b6849.entry.js → p-438e1b8a.entry.js} +1 -1
  254. package/dist/ionic/{p-b752714f.system.entry.js → p-46d400b4.system.entry.js} +1 -1
  255. package/dist/ionic/{p-61d7d7fb.js → p-47b6ba5b.js} +1 -1
  256. package/dist/ionic/{p-b04e4d62.entry.js → p-4d67d27a.entry.js} +1 -1
  257. package/dist/ionic/{p-0b1bc636.entry.js → p-4f3ae45a.entry.js} +1 -1
  258. package/dist/ionic/{p-18b6bd23.system.entry.js → p-517a9885.system.entry.js} +1 -1
  259. package/dist/ionic/p-53ec4f1c.system.js +4 -0
  260. package/dist/ionic/p-5e4eec2e.entry.js +4 -0
  261. package/dist/ionic/{p-57477107.system.js → p-5e745192.system.js} +1 -1
  262. package/dist/ionic/{p-ad019ef0.entry.js → p-5eda1d7d.entry.js} +1 -1
  263. package/dist/ionic/{p-4890093d.js → p-6de472cb.js} +1 -1
  264. package/dist/ionic/{p-08f196ce.system.entry.js → p-6de62649.system.entry.js} +1 -1
  265. package/dist/ionic/p-72f6ff89.js +4 -0
  266. package/dist/ionic/p-765f4dde.entry.js +4 -0
  267. package/dist/ionic/{p-3f6270b3.entry.js → p-78aadecb.entry.js} +1 -1
  268. package/dist/ionic/p-7d92bf15.system.entry.js +4 -0
  269. package/dist/ionic/p-7ee0f3f2.entry.js +4 -0
  270. package/dist/ionic/p-8314281e.system.js +4 -0
  271. package/dist/ionic/p-88d5fbd3.js +4 -0
  272. package/dist/ionic/{p-0e4f2e17.system.js → p-8985cdb6.system.js} +1 -1
  273. package/dist/ionic/{p-d7be6b7e.system.entry.js → p-8acae6b0.system.entry.js} +1 -1
  274. package/dist/ionic/p-8d69a624.entry.js +4 -0
  275. package/dist/ionic/p-8de17614.system.entry.js +4 -0
  276. package/dist/ionic/p-91d33c4a.js +4 -0
  277. package/dist/ionic/p-979d4f5c.system.js +4 -0
  278. package/dist/ionic/p-9b7f0b0f.entry.js +4 -0
  279. package/dist/ionic/p-9e447eb1.system.js +4 -0
  280. package/dist/ionic/p-9f6ee2c0.system.entry.js +4 -0
  281. package/dist/ionic/{p-94389114.system.entry.js → p-a0bb7b92.system.entry.js} +1 -1
  282. package/dist/ionic/{p-f2c21dae.system.js → p-a0d7bb5e.system.js} +1 -1
  283. package/dist/ionic/{p-82045bc1.entry.js → p-a3277a67.entry.js} +1 -1
  284. package/dist/ionic/{p-50880712.entry.js → p-a9978d08.entry.js} +1 -1
  285. package/dist/ionic/{p-3b686a65.system.entry.js → p-ada96dd0.system.entry.js} +1 -1
  286. package/dist/ionic/p-afd6ca9d.entry.js +4 -0
  287. package/dist/ionic/p-b56d0866.system.entry.js +4 -0
  288. package/dist/ionic/{p-67da080d.entry.js → p-b6f9d32a.entry.js} +1 -1
  289. package/dist/ionic/p-c61cc894.js +4 -0
  290. package/dist/ionic/{p-304383f9.system.js → p-cabad15b.system.js} +1 -1
  291. package/dist/ionic/{p-31158892.js → p-cdbeaadc.js} +1 -1
  292. package/dist/ionic/p-d032f825.system.entry.js +4 -0
  293. package/dist/ionic/p-d51674c5.system.js +4 -0
  294. package/dist/ionic/{p-98d82c73.system.js → p-ddbb2d5b.system.js} +1 -1
  295. package/dist/ionic/p-de6f8b28.system.js +4 -0
  296. package/dist/ionic/p-de756e5c.js +4 -0
  297. package/dist/ionic/{p-73ea8f82.system.entry.js → p-dee7c1d0.system.entry.js} +1 -1
  298. package/dist/ionic/p-dfd9432a.entry.js +4 -0
  299. package/dist/ionic/{p-af5cfad2.system.js → p-e24ce1e5.system.js} +1 -1
  300. package/dist/ionic/p-e3584231.system.js +1 -1
  301. package/dist/ionic/p-f0445d82.system.entry.js +4 -0
  302. package/dist/ionic/p-f656e032.system.entry.js +4 -0
  303. package/dist/ionic/{p-17f893be.js → p-f70970cf.js} +1 -1
  304. package/dist/ionic/{p-e553006f.system.entry.js → p-fba0a6e7.system.entry.js} +1 -1
  305. package/dist/ionic/p-feae5133.entry.js +4 -0
  306. package/dist/types/components/checkbox/checkbox.d.ts +1 -0
  307. package/dist/types/components/infinite-scroll/infinite-scroll.d.ts +7 -0
  308. package/dist/types/components/input/input.d.ts +2 -0
  309. package/dist/types/components/radio/radio.d.ts +1 -0
  310. package/dist/types/components/radio-group/radio-group-interface.d.ts +1 -0
  311. package/dist/types/components/radio-group/radio-group.d.ts +8 -1
  312. package/dist/types/components/range/range.d.ts +1 -0
  313. package/dist/types/components/router/router.d.ts +2 -1
  314. package/dist/types/components/select/select.d.ts +6 -1
  315. package/dist/types/components/skeleton-text/skeleton-text.d.ts +9 -1
  316. package/dist/types/components/textarea/textarea.d.ts +2 -0
  317. package/dist/types/components/toast/animations/utils.d.ts +15 -4
  318. package/dist/types/components/toast/gestures/swipe-to-dismiss.d.ts +9 -0
  319. package/dist/types/components/toast/toast-interface.d.ts +2 -0
  320. package/dist/types/components/toast/toast.d.ts +28 -1
  321. package/dist/types/components/toggle/toggle.d.ts +1 -0
  322. package/dist/types/components.d.ts +37 -6
  323. package/dist/types/interface.d.ts +1 -5
  324. package/dist/types/jest.d.ts +5 -0
  325. package/dist/types/utils/animation/animation-interface.d.ts +4 -4
  326. package/dist/types/utils/browser/index.d.ts +11 -2
  327. package/dist/types/utils/forms/compare-with-utils.d.ts +18 -0
  328. package/dist/types/utils/forms/index.d.ts +1 -0
  329. package/dist/types/utils/hardware-back-button.d.ts +4 -0
  330. package/dist/types/utils/overlays.d.ts +1 -0
  331. package/dist/types/utils/slot-mutation-controller.d.ts +2 -2
  332. package/hydrate/index.js +647 -230
  333. package/package.json +1 -1
  334. package/dist/cjs/index-306a7476.js +0 -32
  335. package/dist/collection/components/item/test/text/item.e2e.js +0 -14
  336. package/dist/esm/index-7a14ecec.js +0 -29
  337. package/dist/esm-es5/index-80492ed3.js +0 -4
  338. package/dist/esm-es5/input-shims-0a2e541d.js +0 -4
  339. package/dist/esm-es5/input.utils-2846d430.js +0 -4
  340. package/dist/esm-es5/md.transition-94ac93e1.js +0 -4
  341. package/dist/ionic/p-1d17219f.entry.js +0 -4
  342. package/dist/ionic/p-25b32c3d.entry.js +0 -4
  343. package/dist/ionic/p-2ab4e925.system.entry.js +0 -4
  344. package/dist/ionic/p-2d5aeccc.js +0 -4
  345. package/dist/ionic/p-2d600c25.system.js +0 -4
  346. package/dist/ionic/p-308e1341.js +0 -4
  347. package/dist/ionic/p-34c39c48.entry.js +0 -4
  348. package/dist/ionic/p-3c58a71b.js +0 -4
  349. package/dist/ionic/p-3e960213.system.entry.js +0 -4
  350. package/dist/ionic/p-3fe96156.system.js +0 -4
  351. package/dist/ionic/p-4a31c99f.entry.js +0 -4
  352. package/dist/ionic/p-5a68960f.entry.js +0 -4
  353. package/dist/ionic/p-6470b136.entry.js +0 -4
  354. package/dist/ionic/p-667df818.system.entry.js +0 -4
  355. package/dist/ionic/p-6c37f051.js +0 -4
  356. package/dist/ionic/p-765a08a7.system.entry.js +0 -4
  357. package/dist/ionic/p-7b8d0af2.system.entry.js +0 -4
  358. package/dist/ionic/p-7faba551.system.entry.js +0 -4
  359. package/dist/ionic/p-83af3685.system.js +0 -4
  360. package/dist/ionic/p-856c430d.js +0 -4
  361. package/dist/ionic/p-864c4046.entry.js +0 -4
  362. package/dist/ionic/p-93000a81.system.entry.js +0 -4
  363. package/dist/ionic/p-98b14ece.entry.js +0 -4
  364. package/dist/ionic/p-990ffd0e.js +0 -4
  365. package/dist/ionic/p-a6f9dd7b.entry.js +0 -4
  366. package/dist/ionic/p-a98dc0c1.entry.js +0 -4
  367. package/dist/ionic/p-a9e3b5be.system.entry.js +0 -4
  368. package/dist/ionic/p-ab9456e9.system.entry.js +0 -4
  369. package/dist/ionic/p-b4bad293.system.entry.js +0 -4
  370. package/dist/ionic/p-c3289ef2.entry.js +0 -4
  371. package/dist/ionic/p-c3d09cf2.system.entry.js +0 -4
  372. package/dist/ionic/p-d1cb29a8.system.entry.js +0 -4
  373. package/dist/ionic/p-d43f1f3d.system.js +0 -4
  374. package/dist/ionic/p-d662d908.js +0 -4
  375. package/dist/ionic/p-d9695ad9.system.js +0 -4
  376. package/dist/ionic/p-e4d90573.js +0 -4
  377. package/dist/ionic/p-f51666d3.entry.js +0 -4
  378. package/dist/ionic/p-f54c72b0.system.js +0 -4
  379. package/dist/ionic/p-f7a36cd0.system.js +0 -4
  380. package/dist/ionic/p-f967631d.js +0 -4
  381. /package/dist/esm-es5/{index-7a14ecec.js → index-a5d50daf.js} +0 -0
  382. /package/dist/ionic/{p-0e94957a.system.js → p-792919fd.system.js} +0 -0
  383. /package/dist/ionic/{p-b347cfd1.js → p-7b30edcc.js} +0 -0
@@ -13,6 +13,8 @@ import { getCounterText } from "../input/input.utils";
13
13
  * @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
14
14
  *
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
+ * @slot start - Content to display at the leading edge of the textarea. (EXPERIMENTAL)
17
+ * @slot end - Content to display at the trailing edge of the textarea. (EXPERIMENTAL)
16
18
  */
17
19
  export class Textarea {
18
20
  constructor() {
@@ -121,7 +123,7 @@ export class Textarea {
121
123
  connectedCallback() {
122
124
  const { el } = this;
123
125
  this.legacyFormController = createLegacyFormController(el);
124
- this.slotMutationController = createSlotMutationController(el, 'label', () => forceUpdate(this));
126
+ this.slotMutationController = createSlotMutationController(el, ['label', 'start', 'end'], () => forceUpdate(this));
125
127
  this.notchController = createNotchController(el, () => this.notchSpacerEl, () => this.labelSlot);
126
128
  this.emitStyle();
127
129
  this.debounceChanged();
@@ -191,6 +193,8 @@ export class Textarea {
191
193
  'has-placeholder': this.placeholder !== undefined,
192
194
  'has-value': this.hasValue(),
193
195
  'has-focus': this.hasFocus,
196
+ // TODO(FW-2876): remove this
197
+ legacy: !!this.legacy,
194
198
  });
195
199
  }
196
200
  }
@@ -234,38 +238,15 @@ export class Textarea {
234
238
  if (!this.clearOnEdit) {
235
239
  return;
236
240
  }
237
- /**
238
- * The following keys do not modify the
239
- * contents of the input. As a result, pressing
240
- * them should not edit the textarea.
241
- *
242
- * We can't check to see if the value of the textarea
243
- * was changed because we call checkClearOnEdit
244
- * in a keydown listener, and the key has not yet
245
- * been added to the textarea.
246
- *
247
- * Unlike ion-input, the "Enter" key does modify the
248
- * textarea by adding a new line, so "Enter" is not
249
- * included in the IGNORED_KEYS array.
250
- */
251
- const IGNORED_KEYS = ['Tab', 'Shift', 'Meta', 'Alt', 'Control'];
252
- const pressedIgnoredKey = IGNORED_KEYS.includes(ev.key);
253
241
  /**
254
242
  * Clear the textarea if the control has not been previously cleared
255
243
  * during focus.
256
244
  */
257
- if (!this.didTextareaClearOnEdit && this.hasValue() && !pressedIgnoredKey) {
245
+ if (!this.didTextareaClearOnEdit && this.hasValue() && ev.key !== 'Tab') {
258
246
  this.value = '';
259
247
  this.emitInputChange(ev);
260
248
  }
261
- /**
262
- * Pressing an IGNORED_KEYS first and
263
- * then an allowed key will cause the input to not
264
- * be cleared.
265
- */
266
- if (!pressedIgnoredKey) {
267
- this.didTextareaClearOnEdit = true;
268
- }
249
+ this.didTextareaClearOnEdit = true;
269
250
  }
270
251
  focusChange() {
271
252
  this.emitStyle();
@@ -385,20 +366,41 @@ Developers can use the "legacy" property to continue using the legacy form marku
385
366
  return (h("div", { class: "textarea-bottom" }, this.renderHintText(), this.renderCounter()));
386
367
  }
387
368
  renderTextarea() {
388
- const { inputId, disabled, fill, shape, labelPlacement } = this;
369
+ const { inputId, disabled, fill, shape, labelPlacement, el, hasFocus } = this;
389
370
  const mode = getIonMode(this);
390
371
  const value = this.getValue();
391
372
  const inItem = hostContext('ion-item', this.el);
392
373
  const shouldRenderHighlight = mode === 'md' && fill !== 'outline' && !inItem;
374
+ const hasValue = this.hasValue();
375
+ const hasStartEndSlots = el.querySelector('[slot="start"], [slot="end"]') !== null;
376
+ /**
377
+ * If the label is stacked, it should always sit above the textarea.
378
+ * For floating labels, the label should move above the textarea if
379
+ * the textarea has a value, is focused, or has anything in either
380
+ * the start or end slot.
381
+ *
382
+ * If there is content in the start slot, the label would overlap
383
+ * it if not forced to float. This is also applied to the end slot
384
+ * because with the default or solid fills, the textarea is not
385
+ * vertically centered in the container, but the label is. This
386
+ * causes the slots and label to appear vertically offset from each
387
+ * other when the label isn't floating above the input. This doesn't
388
+ * apply to the outline fill, but this was not accounted for to keep
389
+ * things consistent.
390
+ *
391
+ * TODO(FW-5592): Remove hasStartEndSlots condition
392
+ */
393
+ const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || hasFocus || hasStartEndSlots));
393
394
  return (h(Host, { class: createColorClasses(this.color, {
394
395
  [mode]: true,
395
- 'has-value': this.hasValue(),
396
- 'has-focus': this.hasFocus,
396
+ 'has-value': hasValue,
397
+ 'has-focus': hasFocus,
398
+ 'label-floating': labelShouldFloat,
397
399
  [`textarea-fill-${fill}`]: fill !== undefined,
398
400
  [`textarea-shape-${shape}`]: shape !== undefined,
399
401
  [`textarea-label-placement-${labelPlacement}`]: true,
400
402
  'textarea-disabled': disabled,
401
- }) }, h("label", { class: "textarea-wrapper" }, this.renderLabelContainer(), h("div", { class: "native-wrapper", ref: (el) => (this.textareaWrapper = el) }, h("textarea", Object.assign({ 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 }, this.inheritedAttributes), value)), shouldRenderHighlight && h("div", { class: "textarea-highlight" })), this.renderBottomContent()));
403
+ }) }, h("label", { class: "textarea-wrapper", htmlFor: inputId }, this.renderLabelContainer(), h("div", { class: "textarea-wrapper-inner" }, h("div", { class: "start-slot-wrapper" }, h("slot", { name: "start" })), h("div", { class: "native-wrapper", ref: (el) => (this.textareaWrapper = el) }, h("textarea", Object.assign({ 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 }, this.inheritedAttributes), value)), h("div", { class: "end-slot-wrapper" }, h("slot", { name: "end" }))), shouldRenderHighlight && h("div", { class: "textarea-highlight" })), this.renderBottomContent()));
402
404
  }
403
405
  render() {
404
406
  const { legacyFormController } = this;
@@ -356,9 +356,7 @@
356
356
  }
357
357
 
358
358
  .native-wrapper {
359
- display: flex;
360
359
  position: relative;
361
- flex-grow: 1;
362
360
  width: 100%;
363
361
  height: 100%;
364
362
  }
@@ -429,6 +427,12 @@
429
427
  word-break: break-word;
430
428
  }
431
429
 
430
+ .textarea-wrapper-inner {
431
+ display: flex;
432
+ width: 100%;
433
+ min-height: inherit;
434
+ }
435
+
432
436
  :host(.ion-touched.ion-invalid) {
433
437
  --highlight-color: var(--highlight-color-invalid);
434
438
  }
@@ -704,6 +708,13 @@
704
708
  margin-bottom: 0px;
705
709
  }
706
710
 
711
+ :host(.textarea-label-placement-stacked) ::slotted([slot=start]),
712
+ :host(.textarea-label-placement-stacked) ::slotted([slot=end]),
713
+ :host(.textarea-label-placement-floating) ::slotted([slot=start]),
714
+ :host(.textarea-label-placement-floating) ::slotted([slot=end]) {
715
+ margin-top: 8px;
716
+ }
717
+
707
718
  /**
708
719
  * This makes the label sit over the textarea
709
720
  * when the textarea is blurred and has no value.
@@ -729,9 +740,7 @@
729
740
  /**
730
741
  * This makes the label sit above the textarea.
731
742
  */
732
- :host(.textarea-label-placement-stacked) .label-text-wrapper,
733
- :host(.has-focus.textarea-label-placement-floating) .label-text-wrapper,
734
- :host(.has-value.textarea-label-placement-floating) .label-text-wrapper {
743
+ :host(.label-floating) .label-text-wrapper {
735
744
  transform: translateY(50%) scale(0.75);
736
745
  /**
737
746
  * Label text should not extend
@@ -740,6 +749,29 @@
740
749
  max-width: calc(100% / 0.75);
741
750
  }
742
751
 
752
+ .start-slot-wrapper, .end-slot-wrapper {
753
+ padding-left: 0;
754
+ padding-right: 0;
755
+ padding-top: var(--padding-top);
756
+ padding-bottom: var(--padding-bottom);
757
+ display: flex;
758
+ flex-shrink: 0;
759
+ align-self: start;
760
+ }
761
+
762
+ ::slotted([slot=start]),
763
+ ::slotted([slot=end]) {
764
+ margin-top: 0;
765
+ }
766
+
767
+ ::slotted([slot=start]) {
768
+ margin-inline-end: 16px;
769
+ }
770
+
771
+ ::slotted([slot=end]) {
772
+ margin-inline-start: 16px;
773
+ }
774
+
743
775
  /**
744
776
  * Convert a font size to a dynamic font size.
745
777
  * Fonts that participate in Dynamic Type should use
@@ -1037,9 +1069,7 @@
1037
1069
  }
1038
1070
  }
1039
1071
 
1040
- :host(.textarea-fill-solid.textarea-label-placement-stacked) .label-text-wrapper,
1041
- :host(.has-focus.textarea-fill-solid.textarea-label-placement-floating) .label-text-wrapper,
1042
- :host(.has-value.textarea-fill-solid.textarea-label-placement-floating) .label-text-wrapper {
1072
+ :host(.label-floating.textarea-fill-solid) .label-text-wrapper {
1043
1073
  /**
1044
1074
  * Label text should not extend
1045
1075
  * beyond the bounds of the textarea.
@@ -1193,9 +1223,7 @@
1193
1223
  /**
1194
1224
  * This makes the label sit above the textarea.
1195
1225
  */
1196
- :host(.has-focus.textarea-fill-outline.textarea-label-placement-floating) .label-text-wrapper,
1197
- :host(.has-value.textarea-fill-outline.textarea-label-placement-floating) .label-text-wrapper,
1198
- :host(.textarea-fill-outline.textarea-label-placement-stacked) .label-text-wrapper {
1226
+ :host(.label-floating.textarea-fill-outline) .label-text-wrapper {
1199
1227
  transform: translateY(-32%) scale(0.75);
1200
1228
  margin-left: 0;
1201
1229
  margin-right: 0;
@@ -1227,6 +1255,13 @@
1227
1255
  margin-bottom: 0px;
1228
1256
  }
1229
1257
 
1258
+ :host(.textarea-fill-outline.textarea-label-placement-stacked) ::slotted([slot=start]),
1259
+ :host(.textarea-fill-outline.textarea-label-placement-stacked) ::slotted([slot=end]),
1260
+ :host(.textarea-fill-outline.textarea-label-placement-floating) ::slotted([slot=start]),
1261
+ :host(.textarea-fill-outline.textarea-label-placement-floating) ::slotted([slot=end]) {
1262
+ margin-top: 12px;
1263
+ }
1264
+
1230
1265
  :host(.textarea-fill-outline) .textarea-outline-container {
1231
1266
  left: 0;
1232
1267
  right: 0;
@@ -1362,9 +1397,7 @@
1362
1397
  * the floating/stacked label. We simulate this "cut out"
1363
1398
  * by removing the top border from the notch fragment.
1364
1399
  */
1365
- :host(.has-focus.textarea-fill-outline.textarea-label-placement-floating) .textarea-outline-notch,
1366
- :host(.has-value.textarea-fill-outline.textarea-label-placement-floating) .textarea-outline-notch,
1367
- :host(.textarea-fill-outline.textarea-label-placement-stacked) .textarea-outline-notch {
1400
+ :host(.label-floating.textarea-fill-outline) .textarea-outline-notch {
1368
1401
  border-top: none;
1369
1402
  }
1370
1403
 
@@ -3,6 +3,7 @@
3
3
  */
4
4
  import { createAnimation } from "../../../utils/animation/animation";
5
5
  import { getElementRoot } from "../../../utils/helpers";
6
+ import { getOffsetForMiddlePosition } from "./utils";
6
7
  /**
7
8
  * iOS Toast Enter Animation
8
9
  */
@@ -18,7 +19,7 @@ export const iosEnterAnimation = (baseEl, opts) => {
18
19
  wrapperAnimation.fromTo('transform', 'translateY(-100%)', `translateY(${top})`);
19
20
  break;
20
21
  case 'middle':
21
- const topPosition = Math.floor(baseEl.clientHeight / 2 - wrapperEl.clientHeight / 2);
22
+ const topPosition = getOffsetForMiddlePosition(baseEl.clientHeight, wrapperEl.clientHeight);
22
23
  wrapperEl.style.top = `${topPosition}px`;
23
24
  wrapperAnimation.fromTo('opacity', 0.01, 1);
24
25
  break;
@@ -3,6 +3,7 @@
3
3
  */
4
4
  import { createAnimation } from "../../../utils/animation/animation";
5
5
  import { getElementRoot } from "../../../utils/helpers";
6
+ import { getOffsetForMiddlePosition } from "./utils";
6
7
  /**
7
8
  * MD Toast Enter Animation
8
9
  */
@@ -15,16 +16,16 @@ export const mdEnterAnimation = (baseEl, opts) => {
15
16
  wrapperAnimation.addElement(wrapperEl);
16
17
  switch (position) {
17
18
  case 'top':
18
- wrapperEl.style.top = top;
19
+ wrapperEl.style.setProperty('transform', `translateY(${top})`);
19
20
  wrapperAnimation.fromTo('opacity', 0.01, 1);
20
21
  break;
21
22
  case 'middle':
22
- const topPosition = Math.floor(baseEl.clientHeight / 2 - wrapperEl.clientHeight / 2);
23
+ const topPosition = getOffsetForMiddlePosition(baseEl.clientHeight, wrapperEl.clientHeight);
23
24
  wrapperEl.style.top = `${topPosition}px`;
24
25
  wrapperAnimation.fromTo('opacity', 0.01, 1);
25
26
  break;
26
27
  default:
27
- wrapperEl.style.bottom = bottom;
28
+ wrapperEl.style.setProperty('transform', `translateY(${bottom})`);
28
29
  wrapperAnimation.fromTo('opacity', 0.01, 1);
29
30
  break;
30
31
  }
@@ -7,10 +7,12 @@ import { printIonWarning } from "../../../utils/logging/index";
7
7
  * Calculate the CSS top and bottom position of the toast, to be used
8
8
  * as starting points for the animation keyframes.
9
9
  *
10
- * Note that MD animates bottom-positioned toasts using style.bottom,
11
- * which calculates from the bottom edge of the screen, while iOS uses
12
- * translateY, which calculates from the top edge of the screen. This
13
- * is why the bottom calculates differ slightly between modes.
10
+ * The default animations for both MD and iOS
11
+ * use translateY, which calculates from the
12
+ * top edge of the screen. This behavior impacts
13
+ * how we compute the offset when a toast has
14
+ * position='bottom' since we need to calculate from
15
+ * the bottom edge of the screen instead.
14
16
  *
15
17
  * @param position The value of the toast's position prop.
16
18
  * @param positionAnchor The element the toast should be anchored to,
@@ -25,7 +27,7 @@ export function getAnimationPosition(position, positionAnchor, mode, toast) {
25
27
  */
26
28
  let offset;
27
29
  if (mode === 'md') {
28
- offset = 8;
30
+ offset = position === 'top' ? 8 : -8;
29
31
  }
30
32
  else {
31
33
  offset = position === 'top' ? 10 : -10;
@@ -48,12 +50,7 @@ export function getAnimationPosition(position, positionAnchor, mode, toast) {
48
50
  * to the top edge of the anchor. We want to calculate from the
49
51
  * bottom edge of the screen instead.
50
52
  */
51
- if (mode === 'md') {
52
- offset += win.innerHeight - box.top;
53
- }
54
- else {
55
- offset -= win.innerHeight - box.top;
56
- }
53
+ offset -= win.innerHeight - box.top;
57
54
  }
58
55
  /**
59
56
  * We don't include safe area here because that should already be
@@ -67,9 +64,7 @@ export function getAnimationPosition(position, positionAnchor, mode, toast) {
67
64
  else {
68
65
  return {
69
66
  top: `calc(${offset}px + var(--ion-safe-area-top, 0px))`,
70
- bottom: mode === 'md'
71
- ? `calc(${offset}px + var(--ion-safe-area-bottom, 0px))`
72
- : `calc(${offset}px - var(--ion-safe-area-bottom, 0px))`,
67
+ bottom: `calc(${offset}px - var(--ion-safe-area-bottom, 0px))`,
73
68
  };
74
69
  }
75
70
  }
@@ -83,3 +78,14 @@ function warnIfAnchorIsHidden(positionAnchor, toast) {
83
78
  printIonWarning('The positionAnchor element for ion-toast was found in the DOM, but appears to be hidden. This may lead to unexpected positioning of the toast.', toast);
84
79
  }
85
80
  }
81
+ /**
82
+ * Returns the top offset required to place
83
+ * the toast in the middle of the screen.
84
+ * Only needed when position="toast".
85
+ * @param toastHeight - The height of the ion-toast element
86
+ * @param wrapperHeight - The height of the .toast-wrapper element
87
+ * inside the toast's shadow root.
88
+ */
89
+ export const getOffsetForMiddlePosition = (toastHeight, wrapperHeight) => {
90
+ return Math.floor(toastHeight / 2 - wrapperHeight / 2);
91
+ };
@@ -0,0 +1,267 @@
1
+ /*!
2
+ * (C) Ionic http://ionicframework.com - MIT License
3
+ */
4
+ import { Build } from "@stencil/core";
5
+ import { createAnimation } from "../../../utils/animation/animation";
6
+ import { createGesture } from "../../../utils/gesture/index";
7
+ import { getElementRoot } from "../../../utils/helpers";
8
+ import { OVERLAY_GESTURE_PRIORITY } from "../../../utils/overlays";
9
+ import { getOffsetForMiddlePosition } from "../animations/utils";
10
+ /**
11
+ * Create a gesture that allows the Toast
12
+ * to be swiped to dismiss.
13
+ * @param el - The Toast element
14
+ * @param toastPosition - The last computed position of the Toast. This is computed in the "present" method.
15
+ * @param onDismiss - A callback to fire when the Toast was swiped to dismiss.
16
+ */
17
+ export const createSwipeToDismissGesture = (el, toastPosition, onDismiss) => {
18
+ /**
19
+ * Users should swipe on the visible toast wrapper
20
+ * rather than on ion-toast which covers the entire screen.
21
+ * When testing the class instance the inner wrapper will not
22
+ * be defined. As a result, we use a placeholder element in those environments.
23
+ */
24
+ const wrapperEl = Build.isTesting
25
+ ? document.createElement('div')
26
+ : getElementRoot(el).querySelector('.toast-wrapper');
27
+ const hostElHeight = el.clientHeight;
28
+ const wrapperElBox = wrapperEl.getBoundingClientRect();
29
+ /**
30
+ * The maximum amount that
31
+ * the toast can be swiped. This should
32
+ * account for the wrapper element's height
33
+ * too so the toast can be swiped offscreen
34
+ * completely.
35
+ */
36
+ let MAX_SWIPE_DISTANCE = 0;
37
+ /**
38
+ * The step value at which a toast
39
+ * is eligible for dismissing via gesture.
40
+ */
41
+ const DISMISS_THRESHOLD = 0.5;
42
+ /**
43
+ * The middle position Toast starts 50% of the way
44
+ * through the animation, so we need to use this
45
+ * as the starting point for our step values.
46
+ */
47
+ const STEP_OFFSET = el.position === 'middle' ? 0.5 : 0;
48
+ /**
49
+ * When the Toast is at the top users will be
50
+ * swiping up. As a result, the delta values will be
51
+ * negative numbers which will result in negative steps
52
+ * and thresholds. As a result, we need to make those numbers
53
+ * positive.
54
+ */
55
+ const INVERSION_FACTOR = el.position === 'top' ? -1 : 1;
56
+ /**
57
+ * The top offset that places the
58
+ * toast in the middle of the screen.
59
+ * Only needed when position="middle".
60
+ */
61
+ const topPosition = getOffsetForMiddlePosition(hostElHeight, wrapperElBox.height);
62
+ const SWIPE_UP_DOWN_KEYFRAMES = [
63
+ { offset: 0, transform: `translateY(-${topPosition + wrapperElBox.height}px)` },
64
+ { offset: 0.5, transform: `translateY(0px)` },
65
+ { offset: 1, transform: `translateY(${topPosition + wrapperElBox.height}px)` },
66
+ ];
67
+ const swipeAnimation = createAnimation('toast-swipe-to-dismiss-animation')
68
+ .addElement(wrapperEl)
69
+ /**
70
+ * The specific value here does not actually
71
+ * matter. We just need this to be a positive
72
+ * value so the animation does not jump
73
+ * to the end when the user beings to drag.
74
+ */
75
+ .duration(100);
76
+ switch (el.position) {
77
+ case 'middle':
78
+ MAX_SWIPE_DISTANCE = hostElHeight + wrapperElBox.height;
79
+ swipeAnimation.keyframes(SWIPE_UP_DOWN_KEYFRAMES);
80
+ /**
81
+ * Toast can be swiped up or down but
82
+ * should start in the middle of the screen.
83
+ */
84
+ swipeAnimation.progressStart(true, 0.5);
85
+ break;
86
+ case 'top':
87
+ /**
88
+ * The bottom edge of the wrapper
89
+ * includes the distance between the top
90
+ * of the screen and the top of the wrapper
91
+ * as well as the wrapper height so the wrapper
92
+ * can be dragged fully offscreen.
93
+ */
94
+ MAX_SWIPE_DISTANCE = wrapperElBox.bottom;
95
+ swipeAnimation.keyframes([
96
+ { offset: 0, transform: `translateY(${toastPosition.top})` },
97
+ { offset: 1, transform: 'translateY(-100%)' },
98
+ ]);
99
+ swipeAnimation.progressStart(true, 0);
100
+ break;
101
+ case 'bottom':
102
+ default:
103
+ /**
104
+ * This computes the distance between the
105
+ * top of the wrapper and the bottom of the
106
+ * screen including the height of the wrapper
107
+ * element so it can be dragged fully offscreen.
108
+ */
109
+ MAX_SWIPE_DISTANCE = hostElHeight - wrapperElBox.top;
110
+ swipeAnimation.keyframes([
111
+ { offset: 0, transform: `translateY(${toastPosition.bottom})` },
112
+ { offset: 1, transform: 'translateY(100%)' },
113
+ ]);
114
+ swipeAnimation.progressStart(true, 0);
115
+ break;
116
+ }
117
+ const computeStep = (delta) => {
118
+ return (delta * INVERSION_FACTOR) / MAX_SWIPE_DISTANCE;
119
+ };
120
+ const onMove = (detail) => {
121
+ const step = STEP_OFFSET + computeStep(detail.deltaY);
122
+ swipeAnimation.progressStep(step);
123
+ };
124
+ const onEnd = (detail) => {
125
+ const velocity = detail.velocityY;
126
+ const threshold = ((detail.deltaY + velocity * 1000) / MAX_SWIPE_DISTANCE) * INVERSION_FACTOR;
127
+ /**
128
+ * Disable the gesture for the remainder of the animation.
129
+ * It will be re-enabled if the toast animates back to
130
+ * its initial presented position.
131
+ */
132
+ gesture.enable(false);
133
+ let shouldDismiss = true;
134
+ let playTo = 1;
135
+ let step = 0;
136
+ let remainingDistance = 0;
137
+ if (el.position === 'middle') {
138
+ /**
139
+ * A middle positioned Toast appears
140
+ * in the middle of the screen (at animation offset 0.5).
141
+ * As a result, the threshold will be calculated relative
142
+ * to this starting position. In other words at animation offset 0.5
143
+ * the threshold will be 0. We want the middle Toast to be eligible
144
+ * for dismiss when the user has swiped either half way up or down the
145
+ * screen. As a result, we divide DISMISS_THRESHOLD in half. We also
146
+ * consider when the threshold is a negative in the event the
147
+ * user drags up (since the deltaY will also be negative).
148
+ */
149
+ shouldDismiss = threshold >= DISMISS_THRESHOLD / 2 || threshold <= -DISMISS_THRESHOLD / 2;
150
+ /**
151
+ * Since we are replacing the keyframes
152
+ * below the animation always starts from
153
+ * the beginning of the new keyframes.
154
+ * Similarly, we are always playing to
155
+ * the end of the new keyframes.
156
+ */
157
+ playTo = 1;
158
+ step = 0;
159
+ /**
160
+ * The Toast should animate from wherever its
161
+ * current position is to the desired end state.
162
+ *
163
+ * To begin, we get the current position of the
164
+ * Toast for its starting state.
165
+ */
166
+ const wrapperElBox = wrapperEl.getBoundingClientRect();
167
+ const startOffset = wrapperElBox.top - topPosition;
168
+ const startPosition = `${startOffset}px`;
169
+ /**
170
+ * If the deltaY is negative then the user is swiping
171
+ * up, so the Toast should animate to the top of the screen.
172
+ * If the deltaY is positive then the user is swiping
173
+ * down, so the Toast should animate to the bottom of the screen.
174
+ * We also account for when the deltaY is 0, but realistically
175
+ * that should never happen because it means the user did not drag
176
+ * the toast.
177
+ */
178
+ const offsetFactor = detail.deltaY <= 0 ? -1 : 1;
179
+ const endOffset = (topPosition + wrapperElBox.height) * offsetFactor;
180
+ /**
181
+ * If the Toast should dismiss
182
+ * then we need to figure out which edge of
183
+ * the screen it should animate towards.
184
+ * By default, the Toast will come
185
+ * back to its default state in the
186
+ * middle of the screen.
187
+ */
188
+ const endPosition = shouldDismiss ? `${endOffset}px` : '0px';
189
+ const KEYFRAMES = [
190
+ { offset: 0, transform: `translateY(${startPosition})` },
191
+ { offset: 1, transform: `translateY(${endPosition})` },
192
+ ];
193
+ swipeAnimation.keyframes(KEYFRAMES);
194
+ /**
195
+ * Compute the remaining amount of pixels the
196
+ * toast needs to move to be fully dismissed.
197
+ */
198
+ remainingDistance = endOffset - startOffset;
199
+ }
200
+ else {
201
+ shouldDismiss = threshold >= DISMISS_THRESHOLD;
202
+ playTo = shouldDismiss ? 1 : 0;
203
+ step = computeStep(detail.deltaY);
204
+ /**
205
+ * Compute the remaining amount of pixels the
206
+ * toast needs to move to be fully dismissed.
207
+ */
208
+ const remainingStepAmount = shouldDismiss ? 1 - step : step;
209
+ remainingDistance = remainingStepAmount * MAX_SWIPE_DISTANCE;
210
+ }
211
+ /**
212
+ * The animation speed should depend on how quickly
213
+ * the user flicks the toast across the screen. However,
214
+ * it should be no slower than 200ms.
215
+ * We use Math.abs on the remainingDistance because that value
216
+ * can be negative when swiping up on a middle position toast.
217
+ */
218
+ const duration = Math.min(Math.abs(remainingDistance) / Math.abs(velocity), 200);
219
+ swipeAnimation
220
+ .onFinish(() => {
221
+ if (shouldDismiss) {
222
+ onDismiss();
223
+ swipeAnimation.destroy();
224
+ }
225
+ else {
226
+ if (el.position === 'middle') {
227
+ /**
228
+ * If the toast snapped back to
229
+ * the middle of the screen we need
230
+ * to reset the keyframes
231
+ * so the toast can be swiped
232
+ * up or down again.
233
+ */
234
+ swipeAnimation.keyframes(SWIPE_UP_DOWN_KEYFRAMES).progressStart(true, 0.5);
235
+ }
236
+ else {
237
+ swipeAnimation.progressStart(true, 0);
238
+ }
239
+ /**
240
+ * If the toast did not dismiss then
241
+ * the user should be able to swipe again.
242
+ */
243
+ gesture.enable(true);
244
+ }
245
+ /**
246
+ * This must be a one time callback
247
+ * otherwise a new callback will
248
+ * be added every time onEnd runs.
249
+ */
250
+ }, { oneTimeCallback: true })
251
+ .progressEnd(playTo, step, duration);
252
+ };
253
+ const gesture = createGesture({
254
+ el: wrapperEl,
255
+ gestureName: 'toast-swipe-to-dismiss',
256
+ gesturePriority: OVERLAY_GESTURE_PRIORITY,
257
+ /**
258
+ * Toast only supports vertical swipes.
259
+ * This needs to be updated if we later
260
+ * support horizontal swipes.
261
+ */
262
+ direction: 'y',
263
+ onMove,
264
+ onEnd,
265
+ });
266
+ return gesture;
267
+ };