@ionic/core 8.7.17-dev.11772118942.181221d4 → 8.7.17-dev.11772568074.1d7a4aea

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 (520) hide show
  1. package/components/action-sheet.js +1 -561
  2. package/components/alert.js +1 -610
  3. package/components/animation.js +1 -817
  4. package/components/backdrop.js +1 -72
  5. package/components/button-active.js +1 -64
  6. package/components/button.js +1 -303
  7. package/components/buttons.js +1 -56
  8. package/components/capacitor.js +1 -10
  9. package/components/checkbox.js +1 -261
  10. package/components/config.js +1 -192
  11. package/components/content.js +1 -475
  12. package/components/cubic-bezier.js +1 -87
  13. package/components/data.js +1 -1635
  14. package/components/dir.js +1 -15
  15. package/components/focus-visible.js +1 -72
  16. package/components/framework-delegate.js +1 -137
  17. package/components/gesture-controller.js +1 -192
  18. package/components/haptic.js +1 -155
  19. package/components/hardware-back-button.js +1 -112
  20. package/components/header.js +1 -417
  21. package/components/helpers.js +1 -336
  22. package/components/icon.js +1 -456
  23. package/components/index.d.ts +2 -0
  24. package/components/index.js +1 -115
  25. package/components/index2.js +1 -416
  26. package/components/index3.js +1 -452
  27. package/components/index4.js +1 -118
  28. package/components/index5.js +1 -303
  29. package/components/index6.js +1 -29
  30. package/components/index7.js +1 -164
  31. package/components/index8.js +1 -125
  32. package/components/index9.js +1 -4
  33. package/components/input-shims.js +1 -624
  34. package/components/input.utils.js +1 -144
  35. package/components/ion-accordion-group.js +1 -269
  36. package/components/ion-accordion.js +1 -457
  37. package/components/ion-action-sheet.js +1 -6
  38. package/components/ion-alert.js +1 -6
  39. package/components/ion-app.js +1 -128
  40. package/components/ion-avatar.js +1 -41
  41. package/components/ion-back-button.js +1 -131
  42. package/components/ion-backdrop.js +1 -6
  43. package/components/ion-badge.js +1 -47
  44. package/components/ion-breadcrumb.js +1 -137
  45. package/components/ion-breadcrumbs.js +1 -164
  46. package/components/ion-button.js +1 -6
  47. package/components/ion-buttons.js +1 -6
  48. package/components/ion-card-content.js +1 -45
  49. package/components/ion-card-header.js +1 -56
  50. package/components/ion-card-subtitle.js +1 -48
  51. package/components/ion-card-title.js +1 -48
  52. package/components/ion-card.js +1 -107
  53. package/components/ion-checkbox.js +1 -6
  54. package/components/ion-chip.js +1 -66
  55. package/components/ion-col.js +1 -163
  56. package/components/ion-content.js +1 -6
  57. package/components/ion-datetime-button.js +1 -384
  58. package/components/ion-datetime.js +1 -2046
  59. package/components/ion-fab-button.js +1 -151
  60. package/components/ion-fab-list.js +1 -66
  61. package/components/ion-fab.js +1 -101
  62. package/components/ion-footer.js +1 -159
  63. package/components/ion-grid.js +1 -46
  64. package/components/ion-header.js +1 -6
  65. package/components/ion-icon.js +1 -6
  66. package/components/ion-img.js +1 -124
  67. package/components/ion-infinite-scroll-content.js +1 -70
  68. package/components/ion-infinite-scroll.js +1 -236
  69. package/components/ion-input-otp.js +1 -683
  70. package/components/ion-input-password-toggle.js +1 -129
  71. package/components/ion-input.js +1 -617
  72. package/components/ion-item-divider.js +1 -59
  73. package/components/ion-item-group.js +1 -46
  74. package/components/ion-item-option.js +1 -91
  75. package/components/ion-item-options.js +1 -73
  76. package/components/ion-item-sliding.js +1 -458
  77. package/components/ion-item.js +1 -6
  78. package/components/ion-label.js +1 -6
  79. package/components/ion-list-header.js +1 -6
  80. package/components/ion-list.js +1 -6
  81. package/components/ion-loading.js +1 -344
  82. package/components/ion-menu-button.js +1 -110
  83. package/components/ion-menu-toggle.js +1 -64
  84. package/components/ion-menu.js +1 -745
  85. package/components/ion-modal.js +1 -6
  86. package/components/ion-nav-link.js +1 -64
  87. package/components/ion-nav.js +1 -956
  88. package/components/ion-note.js +1 -47
  89. package/components/ion-picker-column-option.js +1 -6
  90. package/components/ion-picker-column.js +1 -6
  91. package/components/ion-picker-legacy-column.js +1 -6
  92. package/components/ion-picker-legacy.js +1 -343
  93. package/components/ion-picker.js +1 -6
  94. package/components/ion-popover.js +1 -6
  95. package/components/ion-progress-bar.js +1 -101
  96. package/components/ion-radio-group.js +1 -6
  97. package/components/ion-radio.js +1 -6
  98. package/components/ion-range.js +1 -853
  99. package/components/ion-refresher-content.js +1 -89
  100. package/components/ion-refresher.js +1 -751
  101. package/components/ion-reorder-group.js +1 -322
  102. package/components/ion-reorder.js +1 -60
  103. package/components/ion-ripple-effect.js +1 -6
  104. package/components/ion-route-redirect.js +1 -45
  105. package/components/ion-route.js +1 -74
  106. package/components/ion-router-link.js +1 -61
  107. package/components/ion-router-outlet.js +1 -227
  108. package/components/ion-router.js +1 -841
  109. package/components/ion-row.js +1 -36
  110. package/components/ion-searchbar.js +1 -530
  111. package/components/ion-segment-button.js +1 -174
  112. package/components/ion-segment-content.js +1 -35
  113. package/components/ion-segment-view.js +1 -148
  114. package/components/ion-segment.js +1 -602
  115. package/components/ion-select-modal.js +1 -6
  116. package/components/ion-select-option.js +1 -46
  117. package/components/ion-select-popover.js +1 -6
  118. package/components/ion-select.js +1 -1037
  119. package/components/ion-skeleton-text.js +1 -65
  120. package/components/ion-spinner.js +1 -6
  121. package/components/ion-split-pane.js +1 -197
  122. package/components/ion-tab-bar.js +1 -115
  123. package/components/ion-tab-button.js +1 -128
  124. package/components/ion-tab.js +1 -91
  125. package/components/ion-tabs.js +1 -205
  126. package/components/ion-text.js +1 -42
  127. package/components/ion-textarea.js +1 -554
  128. package/components/ion-thumbnail.js +1 -36
  129. package/components/ion-title.js +1 -6
  130. package/components/ion-toast.js +1 -941
  131. package/components/ion-toggle.js +1 -361
  132. package/components/ion-toolbar.js +1 -6
  133. package/components/ionic-global.js +1 -144
  134. package/components/ios.transition.js +1 -672
  135. package/components/item.js +1 -302
  136. package/components/keyboard-controller.js +1 -162
  137. package/components/keyboard.js +1 -141
  138. package/components/keyboard2.js +1 -76
  139. package/components/label.js +1 -100
  140. package/components/list-header.js +1 -47
  141. package/components/list.js +1 -68
  142. package/components/lock-controller.js +1 -35
  143. package/components/md.transition.js +1 -51
  144. package/components/menu-toggle-util.js +1 -9
  145. package/components/modal.js +1 -2674
  146. package/components/notch-controller.js +1 -150
  147. package/components/overlays.js +1 -912
  148. package/components/picker-column-option.js +1 -136
  149. package/components/picker-column.js +1 -595
  150. package/components/picker-column2.js +1 -377
  151. package/components/picker.js +1 -498
  152. package/components/popover.js +1 -1502
  153. package/components/radio-group.js +1 -287
  154. package/components/radio.js +1 -229
  155. package/components/refresher.utils.js +1 -193
  156. package/components/ripple-effect.js +1 -109
  157. package/components/select-modal.js +1 -196
  158. package/components/select-popover.js +1 -189
  159. package/components/spinner.js +1 -224
  160. package/components/status-tap.js +1 -36
  161. package/components/swipe-back.js +1 -75
  162. package/components/theme.js +1 -40
  163. package/components/title.js +1 -70
  164. package/components/toolbar.js +1 -89
  165. package/components/validity.js +1 -14
  166. package/components/watch-options.js +1 -44
  167. package/dist/cjs/{animation-Bt3H9L1C.js → animation-Dg4yiuR2.js} +1 -1
  168. package/dist/cjs/app-globals-CLI8xCmk.js +11 -0
  169. package/dist/cjs/{button-active-CMc8cD90.js → button-active-FscMI17-.js} +1 -1
  170. package/dist/cjs/{config-C5fsO43a.js → config-BukYi_pW.js} +1 -1
  171. package/dist/cjs/{data-JwZKaIQB.js → data-BYlBjkMU.js} +1 -1
  172. package/dist/cjs/{framework-delegate-DMJRBuDi.js → framework-delegate-CRgp8o_p.js} +1 -1
  173. package/dist/cjs/{hardware-back-button-VCK4V3mG.js → hardware-back-button-C4rMJ5uI.js} +1 -1
  174. package/dist/cjs/{helpers-DrTqNghc.js → helpers-CxTYJdbT.js} +1 -1
  175. package/dist/cjs/{index-094mMFB-.js → index-C845Ti6K.js} +4 -4
  176. package/dist/cjs/{index-DrMUZJj6.js → index-CFUwM5x_.js} +5 -5
  177. package/dist/cjs/{index-D6Wc6v08.js → index-CqT-2gKy.js} +503 -382
  178. package/dist/cjs/{index-CO6eryBo.js → index-MbaBbWXk.js} +2 -2
  179. package/dist/cjs/{index-C534ULug.js → index-YcSftOMz.js} +2 -2
  180. package/dist/cjs/index.cjs.js +12 -12
  181. package/dist/cjs/{input-shims-CW0KUFTQ.js → input-shims-DlFhYYTs.js} +3 -3
  182. package/dist/cjs/{input.utils-B_QROI2g.js → input.utils-DmeJ8dmo.js} +2 -2
  183. package/dist/cjs/ion-accordion_2.cjs.entry.js +23 -15
  184. package/dist/cjs/ion-action-sheet.cjs.entry.js +21 -15
  185. package/dist/cjs/ion-alert.cjs.entry.js +25 -17
  186. package/dist/cjs/ion-app_8.cjs.entry.js +44 -40
  187. package/dist/cjs/ion-avatar_3.cjs.entry.js +12 -12
  188. package/dist/cjs/ion-back-button.cjs.entry.js +7 -7
  189. package/dist/cjs/ion-backdrop.cjs.entry.js +6 -6
  190. package/dist/cjs/ion-breadcrumb_2.cjs.entry.js +20 -14
  191. package/dist/cjs/ion-button_2.cjs.entry.js +36 -18
  192. package/dist/cjs/ion-card_5.cjs.entry.js +23 -23
  193. package/dist/cjs/ion-checkbox.cjs.entry.js +7 -7
  194. package/dist/cjs/ion-chip.cjs.entry.js +6 -6
  195. package/dist/cjs/ion-col_3.cjs.entry.js +8 -8
  196. package/dist/cjs/ion-datetime-button.cjs.entry.js +8 -8
  197. package/dist/cjs/ion-datetime_3.cjs.entry.js +67 -39
  198. package/dist/cjs/ion-fab_3.cjs.entry.js +17 -13
  199. package/dist/cjs/ion-img.cjs.entry.js +8 -6
  200. package/dist/cjs/ion-infinite-scroll_2.cjs.entry.js +17 -13
  201. package/dist/cjs/ion-input-otp.cjs.entry.js +16 -10
  202. package/dist/cjs/ion-input-password-toggle.cjs.entry.js +9 -7
  203. package/dist/cjs/ion-input.cjs.entry.js +21 -13
  204. package/dist/cjs/ion-item-option_3.cjs.entry.js +17 -15
  205. package/dist/cjs/ion-item_8.cjs.entry.js +42 -36
  206. package/dist/cjs/ion-loading.cjs.entry.js +18 -14
  207. package/dist/cjs/ion-menu_3.cjs.entry.js +30 -22
  208. package/dist/cjs/ion-modal.cjs.entry.js +55 -40
  209. package/dist/cjs/ion-nav_2.cjs.entry.js +14 -10
  210. package/dist/cjs/ion-picker-column-option.cjs.entry.js +10 -8
  211. package/dist/cjs/ion-picker-column.cjs.entry.js +11 -7
  212. package/dist/cjs/ion-picker.cjs.entry.js +6 -6
  213. package/dist/cjs/ion-popover.cjs.entry.js +21 -15
  214. package/dist/cjs/ion-progress-bar.cjs.entry.js +7 -7
  215. package/dist/cjs/ion-radio_2.cjs.entry.js +17 -13
  216. package/dist/cjs/ion-range.cjs.entry.js +29 -15
  217. package/dist/cjs/ion-refresher_2.cjs.entry.js +45 -14
  218. package/dist/cjs/ion-reorder_2.cjs.entry.js +13 -11
  219. package/dist/cjs/ion-ripple-effect.cjs.entry.js +4 -4
  220. package/dist/cjs/ion-route_4.cjs.entry.js +20 -10
  221. package/dist/cjs/ion-searchbar.cjs.entry.js +22 -12
  222. package/dist/cjs/ion-segment-content.cjs.entry.js +3 -3
  223. package/dist/cjs/ion-segment-view.cjs.entry.js +5 -5
  224. package/dist/cjs/ion-segment_2.cjs.entry.js +26 -16
  225. package/dist/cjs/ion-select-modal.cjs.entry.js +12 -12
  226. package/dist/cjs/ion-select_3.cjs.entry.js +29 -21
  227. package/dist/cjs/ion-spinner.cjs.entry.js +4 -4
  228. package/dist/cjs/ion-split-pane.cjs.entry.js +15 -9
  229. package/dist/cjs/ion-tab-bar_2.cjs.entry.js +14 -12
  230. package/dist/cjs/ion-tab_2.cjs.entry.js +10 -8
  231. package/dist/cjs/ion-text.cjs.entry.js +4 -4
  232. package/dist/cjs/ion-textarea.cjs.entry.js +18 -12
  233. package/dist/cjs/ion-toast.cjs.entry.js +21 -15
  234. package/dist/cjs/ion-toggle.cjs.entry.js +10 -8
  235. package/dist/cjs/{ionic-global-HMVqOFGO.js → ionic-global-Bc3kJi1Z.js} +1 -1
  236. package/dist/cjs/ionic.cjs.js +5 -5
  237. package/dist/cjs/{ios.transition-BOt_uW73.js → ios.transition-trBiC95R.js} +4 -4
  238. package/dist/cjs/loader.cjs.js +4 -4
  239. package/dist/cjs/{md.transition-Dt968VXB.js → md.transition-CUQECuvD.js} +4 -4
  240. package/dist/cjs/{notch-controller-Bzqhjm4f.js → notch-controller-sD-lTpdc.js} +1 -1
  241. package/dist/cjs/{overlays-B2b-TTbl.js → overlays-C2jiBSNQ.js} +5 -5
  242. package/dist/cjs/{status-tap-g0sWWkXk.js → status-tap-CCJk5VgT.js} +3 -3
  243. package/dist/cjs/{swipe-back-BIayeNOD.js → swipe-back-BGhTQ1CU.js} +2 -2
  244. package/dist/collection/collection-manifest.json +2 -2
  245. package/dist/collection/components/accordion-group/accordion-group.js +4 -2
  246. package/dist/collection/components/action-sheet/action-sheet.js +20 -10
  247. package/dist/collection/components/alert/alert.js +24 -12
  248. package/dist/collection/components/back-button/back-button.js +4 -2
  249. package/dist/collection/components/badge/badge.js +2 -1
  250. package/dist/collection/components/breadcrumb/breadcrumb.js +8 -4
  251. package/dist/collection/components/breadcrumbs/breadcrumbs.js +4 -2
  252. package/dist/collection/components/button/button.js +6 -3
  253. package/dist/collection/components/card/card.js +6 -3
  254. package/dist/collection/components/card-header/card-header.js +2 -1
  255. package/dist/collection/components/card-subtitle/card-subtitle.js +2 -1
  256. package/dist/collection/components/card-title/card-title.js +2 -1
  257. package/dist/collection/components/checkbox/checkbox.js +4 -2
  258. package/dist/collection/components/chip/chip.js +2 -1
  259. package/dist/collection/components/content/content.js +8 -4
  260. package/dist/collection/components/datetime/datetime.js +34 -15
  261. package/dist/collection/components/datetime-button/datetime-button.js +2 -1
  262. package/dist/collection/components/fab-button/fab-button.js +6 -3
  263. package/dist/collection/components/infinite-scroll-content/infinite-scroll-content.js +4 -2
  264. package/dist/collection/components/input/input.js +11 -6
  265. package/dist/collection/components/input-otp/input-otp.js +8 -4
  266. package/dist/collection/components/input-password-toggle/input-password-toggle.js +4 -2
  267. package/dist/collection/components/item/item.js +6 -3
  268. package/dist/collection/components/item-divider/item-divider.js +2 -1
  269. package/dist/collection/components/item-option/item-option.js +2 -1
  270. package/dist/collection/components/item-options/item-options.js +2 -1
  271. package/dist/collection/components/item-sliding/item-sliding.js +2 -1
  272. package/dist/collection/components/label/label.js +6 -3
  273. package/dist/collection/components/list-header/list-header.js +2 -1
  274. package/dist/collection/components/loading/loading.js +22 -11
  275. package/dist/collection/components/menu/menu.js +10 -5
  276. package/dist/collection/components/menu-button/menu-button.js +2 -1
  277. package/dist/collection/components/modal/gestures/sheet.js +32 -21
  278. package/dist/collection/components/modal/modal.js +35 -20
  279. package/dist/collection/components/nav/nav.js +89 -45
  280. package/dist/collection/components/nav-link/nav-link.js +9 -5
  281. package/dist/collection/components/note/note.js +2 -1
  282. package/dist/collection/components/picker/picker.js +2 -1
  283. package/dist/collection/components/picker-column/picker-column.js +6 -3
  284. package/dist/collection/components/picker-column-option/picker-column-option.js +2 -1
  285. package/dist/collection/components/picker-legacy/picker.js +24 -12
  286. package/dist/collection/components/picker-legacy-column/picker-column.js +4 -2
  287. package/dist/collection/components/popover/popover.js +33 -17
  288. package/dist/collection/components/progress-bar/progress-bar.js +2 -1
  289. package/dist/collection/components/radio/radio.js +2 -1
  290. package/dist/collection/components/radio-group/radio-group.js +6 -3
  291. package/dist/collection/components/range/range.js +14 -7
  292. package/dist/collection/components/refresher/refresher.js +73 -5
  293. package/dist/collection/components/refresher-content/refresher-content.js +8 -4
  294. package/dist/collection/components/reorder-group/reorder-group.js +6 -3
  295. package/dist/collection/components/route/route.js +4 -2
  296. package/dist/collection/components/router/router.js +10 -5
  297. package/dist/collection/components/router-link/router-link.js +6 -3
  298. package/dist/collection/components/router-outlet/router-outlet.js +18 -9
  299. package/dist/collection/components/searchbar/searchbar.js +11 -6
  300. package/dist/collection/components/segment/segment.js +10 -5
  301. package/dist/collection/components/segment-button/segment-button.js +4 -2
  302. package/dist/collection/components/segment-view/segment-view.js +2 -1
  303. package/dist/collection/components/select/select.js +10 -5
  304. package/dist/collection/components/select-modal/select-modal.js +2 -1
  305. package/dist/collection/components/select-popover/select-popover.js +2 -1
  306. package/dist/collection/components/skeleton-text/skeleton-text.js +2 -1
  307. package/dist/collection/components/spinner/spinner.js +4 -2
  308. package/dist/collection/components/tab/tab.js +4 -2
  309. package/dist/collection/components/tab-bar/tab-bar.js +4 -2
  310. package/dist/collection/components/tab-button/tab-button.js +4 -2
  311. package/dist/collection/components/tabs/tabs.js +4 -2
  312. package/dist/collection/components/text/text.js +2 -1
  313. package/dist/collection/components/textarea/textarea.js +6 -3
  314. package/dist/collection/components/title/title.js +4 -2
  315. package/dist/collection/components/toast/toast.js +34 -17
  316. package/dist/collection/components/toggle/toggle.js +4 -2
  317. package/dist/collection/components/toolbar/toolbar.js +2 -1
  318. package/dist/docs.d.ts +37 -0
  319. package/dist/docs.json +835 -381
  320. package/dist/esm/{animation-Dt8bGnA-.js → animation-CnGMT4ji.js} +1 -1
  321. package/dist/esm/app-globals-DhZjtldk.js +9 -0
  322. package/dist/esm/{button-active-L570Swow.js → button-active-BBx21brx.js} +1 -1
  323. package/dist/esm/{config-mCdtaoPe.js → config-TO1rZH52.js} +1 -1
  324. package/dist/esm/{data-DCORV9FH.js → data-B9iGR5YO.js} +1 -1
  325. package/dist/esm/{framework-delegate-BYawdMXj.js → framework-delegate-CyxE1S_P.js} +1 -1
  326. package/dist/esm/{hardware-back-button-CPLxO-Ev.js → hardware-back-button-CTe4XmL7.js} +1 -1
  327. package/dist/esm/{helpers-DEn3pfjm.js → helpers-Tl8jw6S2.js} +1 -1
  328. package/dist/esm/{index-r2D9DEro.js → index-B-hkiOUh.js} +4 -4
  329. package/dist/esm/{index-CvDIirVx.js → index-B2KwgBLx.js} +5 -5
  330. package/dist/esm/{index-ceb5RaMT.js → index-BtUdxPjv.js} +2 -2
  331. package/dist/esm/{index-C8IsBmNU.js → index-IGIE5vDm.js} +503 -382
  332. package/dist/esm/{index-Bs3kT4bc.js → index-hW6eNZ3o.js} +2 -2
  333. package/dist/esm/index.js +12 -12
  334. package/dist/esm/{input-shims-DyOpfTg6.js → input-shims-C1hAaHcP.js} +3 -3
  335. package/dist/esm/{input.utils-DrvTa8gz.js → input.utils-Bxa_DQ7-.js} +2 -2
  336. package/dist/esm/ion-accordion_2.entry.js +23 -15
  337. package/dist/esm/ion-action-sheet.entry.js +21 -15
  338. package/dist/esm/ion-alert.entry.js +25 -17
  339. package/dist/esm/ion-app_8.entry.js +44 -40
  340. package/dist/esm/ion-avatar_3.entry.js +12 -12
  341. package/dist/esm/ion-back-button.entry.js +7 -7
  342. package/dist/esm/ion-backdrop.entry.js +6 -6
  343. package/dist/esm/ion-breadcrumb_2.entry.js +20 -14
  344. package/dist/esm/ion-button_2.entry.js +36 -18
  345. package/dist/esm/ion-card_5.entry.js +23 -23
  346. package/dist/esm/ion-checkbox.entry.js +7 -7
  347. package/dist/esm/ion-chip.entry.js +6 -6
  348. package/dist/esm/ion-col_3.entry.js +8 -8
  349. package/dist/esm/ion-datetime-button.entry.js +8 -8
  350. package/dist/esm/ion-datetime_3.entry.js +67 -39
  351. package/dist/esm/ion-fab_3.entry.js +17 -13
  352. package/dist/esm/ion-img.entry.js +8 -6
  353. package/dist/esm/ion-infinite-scroll_2.entry.js +17 -13
  354. package/dist/esm/ion-input-otp.entry.js +16 -10
  355. package/dist/esm/ion-input-password-toggle.entry.js +9 -7
  356. package/dist/esm/ion-input.entry.js +21 -13
  357. package/dist/esm/ion-item-option_3.entry.js +17 -15
  358. package/dist/esm/ion-item_8.entry.js +42 -36
  359. package/dist/esm/ion-loading.entry.js +18 -14
  360. package/dist/esm/ion-menu_3.entry.js +30 -22
  361. package/dist/esm/ion-modal.entry.js +55 -40
  362. package/dist/esm/ion-nav_2.entry.js +14 -10
  363. package/dist/esm/ion-picker-column-option.entry.js +10 -8
  364. package/dist/esm/ion-picker-column.entry.js +11 -7
  365. package/dist/esm/ion-picker.entry.js +6 -6
  366. package/dist/esm/ion-popover.entry.js +21 -15
  367. package/dist/esm/ion-progress-bar.entry.js +7 -7
  368. package/dist/esm/ion-radio_2.entry.js +17 -13
  369. package/dist/esm/ion-range.entry.js +29 -15
  370. package/dist/esm/ion-refresher_2.entry.js +45 -14
  371. package/dist/esm/ion-reorder_2.entry.js +13 -11
  372. package/dist/esm/ion-ripple-effect.entry.js +4 -4
  373. package/dist/esm/ion-route_4.entry.js +20 -10
  374. package/dist/esm/ion-searchbar.entry.js +22 -12
  375. package/dist/esm/ion-segment-content.entry.js +3 -3
  376. package/dist/esm/ion-segment-view.entry.js +5 -5
  377. package/dist/esm/ion-segment_2.entry.js +26 -16
  378. package/dist/esm/ion-select-modal.entry.js +12 -12
  379. package/dist/esm/ion-select_3.entry.js +29 -21
  380. package/dist/esm/ion-spinner.entry.js +4 -4
  381. package/dist/esm/ion-split-pane.entry.js +15 -9
  382. package/dist/esm/ion-tab-bar_2.entry.js +14 -12
  383. package/dist/esm/ion-tab_2.entry.js +10 -8
  384. package/dist/esm/ion-text.entry.js +4 -4
  385. package/dist/esm/ion-textarea.entry.js +18 -12
  386. package/dist/esm/ion-toast.entry.js +21 -15
  387. package/dist/esm/ion-toggle.entry.js +10 -8
  388. package/dist/esm/{ionic-global-CDrldh-5.js → ionic-global-DfbeLwcV.js} +1 -1
  389. package/dist/esm/ionic.js +6 -6
  390. package/dist/esm/{ios.transition-BDzw0_Hm.js → ios.transition--aMF-pDH.js} +4 -4
  391. package/dist/esm/loader.js +5 -5
  392. package/dist/esm/{md.transition-BzDYi3qq.js → md.transition-BEVbfm8j.js} +4 -4
  393. package/dist/esm/{notch-controller-BwelN_JM.js → notch-controller-DAcvKU57.js} +1 -1
  394. package/dist/esm/{overlays-D5YkFThA.js → overlays-F8GHPo-e.js} +5 -5
  395. package/dist/esm/{status-tap-5DQ7Fc4V.js → status-tap-BfJqFSLF.js} +3 -3
  396. package/dist/esm/{swipe-back-BKw2CAHc.js → swipe-back-BZBFwTQV.js} +2 -2
  397. package/dist/html.html-data.json +109 -109
  398. package/dist/ionic/index.esm.js +1 -1
  399. package/dist/ionic/ionic.esm.js +1 -1
  400. package/dist/ionic/{p-316c0420.entry.js → p-025d2d32.entry.js} +1 -1
  401. package/dist/ionic/p-02acdef4.entry.js +4 -0
  402. package/dist/ionic/p-04e2c388.entry.js +4 -0
  403. package/dist/ionic/{p-370e4237.entry.js → p-074344b8.entry.js} +1 -1
  404. package/dist/ionic/p-0761b4d3.entry.js +4 -0
  405. package/dist/ionic/p-13ade5c8.entry.js +4 -0
  406. package/dist/ionic/p-1b02923f.entry.js +4 -0
  407. package/dist/ionic/p-1bd477a9.entry.js +4 -0
  408. package/dist/ionic/{p-d2489bf2.entry.js → p-1fa1406c.entry.js} +1 -1
  409. package/dist/ionic/{p-46d74291.entry.js → p-1fd588a7.entry.js} +1 -1
  410. package/dist/ionic/p-239a27a4.entry.js +4 -0
  411. package/dist/ionic/{p-94de5cfa.entry.js → p-277abec1.entry.js} +1 -1
  412. package/dist/ionic/{p-dd1aef77.entry.js → p-28d7852f.entry.js} +1 -1
  413. package/dist/ionic/{p-49d06882.entry.js → p-301c43f8.entry.js} +1 -1
  414. package/dist/ionic/{p-79bd78f9.entry.js → p-370a60ee.entry.js} +1 -1
  415. package/dist/ionic/p-3e143d1d.entry.js +4 -0
  416. package/dist/ionic/p-4431ef7e.entry.js +4 -0
  417. package/dist/ionic/p-463767ce.entry.js +4 -0
  418. package/dist/ionic/p-4f888343.entry.js +4 -0
  419. package/dist/ionic/p-51c11c47.entry.js +4 -0
  420. package/dist/ionic/p-56050077.entry.js +4 -0
  421. package/dist/ionic/p-6a3a5aae.entry.js +4 -0
  422. package/dist/ionic/p-6b97f2a3.entry.js +4 -0
  423. package/dist/ionic/{p-51a60e0f.entry.js → p-7c72d482.entry.js} +1 -1
  424. package/dist/ionic/p-7d20f4f8.entry.js +4 -0
  425. package/dist/ionic/{p-11aa58d6.entry.js → p-80cac7a2.entry.js} +1 -1
  426. package/dist/ionic/p-91fc7352.entry.js +4 -0
  427. package/dist/ionic/p-93845421.entry.js +4 -0
  428. package/dist/ionic/{p-3a6caca9.entry.js → p-964090ef.entry.js} +1 -1
  429. package/dist/ionic/p-96a2e768.entry.js +4 -0
  430. package/dist/ionic/{p-d126e8d3.entry.js → p-9745651b.entry.js} +1 -1
  431. package/dist/ionic/{p-f9061316.entry.js → p-9802c88e.entry.js} +1 -1
  432. package/dist/ionic/{p-582824c5.entry.js → p-9833cf63.entry.js} +1 -1
  433. package/dist/ionic/{p-675b1a31.entry.js → p-9fae83d8.entry.js} +1 -1
  434. package/dist/ionic/{p-CwgG81ZD.js → p-B8xlpH8p.js} +1 -1
  435. package/dist/ionic/{p-C7hRNDhM.js → p-BAt5H1ac.js} +1 -1
  436. package/dist/ionic/p-BW_TRJm8.js +4 -0
  437. package/dist/ionic/{p-DDb5r57F.js → p-Bum7H1fw.js} +1 -1
  438. package/dist/ionic/{p-D0dMcSkw.js → p-BvFYtOdE.js} +1 -1
  439. package/dist/ionic/{p-Dc45iWE4.js → p-BxIcPWoV.js} +1 -1
  440. package/dist/ionic/{p-BYEqWnSg.js → p-C0JvVFMv.js} +1 -1
  441. package/dist/ionic/{p-CTfR9YZG.js → p-CGmVTdWh.js} +1 -1
  442. package/dist/ionic/{p-BOVrCkpJ.js → p-CYbRmDdy.js} +1 -1
  443. package/dist/ionic/{p-D-eFFUkA.js → p-CmFz1Mjc.js} +1 -1
  444. package/dist/ionic/p-CtA-yJYy.js +4 -0
  445. package/dist/ionic/p-D8HJQ1qq.js +4 -0
  446. package/dist/ionic/{p-B0q1YL7N.js → p-DB_iPQC-.js} +1 -1
  447. package/dist/ionic/{p-DNcfiJwE.js → p-DLbbmF9h.js} +1 -1
  448. package/dist/ionic/{p-DdR6rpbR.js → p-DTPR1Wpn.js} +1 -1
  449. package/dist/ionic/{p-DCv9sLH2.js → p-DjriolRs.js} +1 -1
  450. package/dist/ionic/p-DtVZDHlS.js +4 -0
  451. package/dist/ionic/{p-QHYY4sjU.js → p-GWUGgWx6.js} +1 -1
  452. package/dist/ionic/p-IGIE5vDm.js +5 -0
  453. package/dist/ionic/{p-BFvmZNyx.js → p-NFFyoJ4Q.js} +1 -1
  454. package/dist/ionic/{p-86f53961.entry.js → p-a287e18e.entry.js} +1 -1
  455. package/dist/ionic/p-a805674e.entry.js +4 -0
  456. package/dist/ionic/p-a81ae2cd.entry.js +4 -0
  457. package/dist/ionic/{p-da7d04cc.entry.js → p-a84f2d21.entry.js} +1 -1
  458. package/dist/ionic/{p-dbbe606a.entry.js → p-b2d5238b.entry.js} +1 -1
  459. package/dist/ionic/{p-d1f54e28.entry.js → p-b440381f.entry.js} +1 -1
  460. package/dist/ionic/{p-72c38b88.entry.js → p-b4d52b58.entry.js} +1 -1
  461. package/dist/ionic/{p-2a939845.entry.js → p-b67a2114.entry.js} +1 -1
  462. package/dist/ionic/{p-c73627c8.entry.js → p-bced1f3e.entry.js} +1 -1
  463. package/dist/ionic/{p-9a2d390d.entry.js → p-c1c9b2bb.entry.js} +1 -1
  464. package/dist/ionic/{p-f8f22cc0.entry.js → p-c3e65e45.entry.js} +1 -1
  465. package/dist/ionic/p-c76cc21d.entry.js +4 -0
  466. package/dist/ionic/{p-b0a7585c.entry.js → p-ca31010f.entry.js} +1 -1
  467. package/dist/ionic/p-cbf245b5.entry.js +4 -0
  468. package/dist/ionic/p-d68b665a.entry.js +4 -0
  469. package/dist/ionic/{p-9575b654.entry.js → p-e663bc5a.entry.js} +1 -1
  470. package/dist/ionic/p-efe86ed9.entry.js +4 -0
  471. package/dist/ionic/{p-ac4eb91d.entry.js → p-f5dfb9a3.entry.js} +1 -1
  472. package/dist/ionic/{p-DbQ5QkTP.js → p-gbVXD275.js} +1 -1
  473. package/dist/ionic/p-hNN3VvaC.js +4 -0
  474. package/dist/types/components/datetime/datetime.d.ts +9 -0
  475. package/dist/types/components/header/header.utils.d.ts +2 -1
  476. package/dist/types/components/modal/modal-interface.d.ts +5 -1
  477. package/dist/types/components/modal/modal.d.ts +5 -0
  478. package/dist/types/components/refresher/refresher-interface.d.ts +7 -0
  479. package/dist/types/components/refresher/refresher.d.ts +16 -3
  480. package/dist/types/components.d.ts +927 -189
  481. package/dist/types/interface.d.ts +1 -1
  482. package/dist/types/stencil-public-runtime.d.ts +126 -14
  483. package/dist/types/utils/gesture/listener.d.ts +2 -1
  484. package/hydrate/index.d.ts +12 -0
  485. package/hydrate/index.js +5202 -1327
  486. package/hydrate/index.mjs +5201 -1328
  487. package/package.json +2 -2
  488. package/dist/cjs/app-globals-Ciccnk9_.js +0 -10
  489. package/dist/esm/app-globals-BDSf8fOA.js +0 -8
  490. package/dist/ionic/p-012212e4.entry.js +0 -4
  491. package/dist/ionic/p-074839fc.entry.js +0 -4
  492. package/dist/ionic/p-0dfa5a37.entry.js +0 -4
  493. package/dist/ionic/p-0f418a37.entry.js +0 -4
  494. package/dist/ionic/p-11518b31.entry.js +0 -4
  495. package/dist/ionic/p-1838bed5.entry.js +0 -4
  496. package/dist/ionic/p-29721c43.entry.js +0 -4
  497. package/dist/ionic/p-31f7095f.entry.js +0 -4
  498. package/dist/ionic/p-34642fa1.entry.js +0 -4
  499. package/dist/ionic/p-35696017.entry.js +0 -4
  500. package/dist/ionic/p-40c261a3.entry.js +0 -4
  501. package/dist/ionic/p-4e41ea20.entry.js +0 -4
  502. package/dist/ionic/p-6241ce47.entry.js +0 -4
  503. package/dist/ionic/p-639dd543.entry.js +0 -4
  504. package/dist/ionic/p-6444c606.entry.js +0 -4
  505. package/dist/ionic/p-6d070558.entry.js +0 -4
  506. package/dist/ionic/p-7268efa5.entry.js +0 -4
  507. package/dist/ionic/p-7babec72.entry.js +0 -4
  508. package/dist/ionic/p-BKc55Xev.js +0 -4
  509. package/dist/ionic/p-Bmgaetn_.js +0 -4
  510. package/dist/ionic/p-C8IsBmNU.js +0 -5
  511. package/dist/ionic/p-CJxh_yLS.js +0 -4
  512. package/dist/ionic/p-DUt5fQmA.js +0 -4
  513. package/dist/ionic/p-DZRJwG4S.js +0 -4
  514. package/dist/ionic/p-a127bee2.entry.js +0 -4
  515. package/dist/ionic/p-b3d44509.entry.js +0 -4
  516. package/dist/ionic/p-cc45bcbc.entry.js +0 -4
  517. package/dist/ionic/p-d0a2a1ab.entry.js +0 -4
  518. package/dist/ionic/p-d3014190.entry.js +0 -4
  519. package/dist/ionic/p-db82892c.entry.js +0 -4
  520. package/dist/ionic/p-e1d1f3cc.entry.js +0 -4
@@ -1,2677 +1,4 @@
1
1
  /*!
2
2
  * (C) Ionic http://ionicframework.com - MIT License
3
3
  */
4
- import { proxyCustomElement, HTMLElement, createEvent, writeTask, h, Host } from '@stencil/core/internal/client';
5
- import { a as findClosestIonContent, i as isIonContent, d as disableContentScrollY, r as resetContentScrollY, f as findIonContent, p as printIonContentErrorMsg } from './index8.js';
6
- import { C as CoreDelegate, a as attachComponent, d as detachComponent } from './framework-delegate.js';
7
- import { f as clamp, g as getElementRoot, r as raf, d as inheritAttributes, k as hasLazyBuild } from './helpers.js';
8
- import { c as createLockController } from './lock-controller.js';
9
- import { p as printIonWarning, c as config } from './index4.js';
10
- import { g as getCapacitor } from './capacitor.js';
11
- import { G as GESTURE, O as OVERLAY_GESTURE_PRIORITY, F as FOCUS_TRAP_DISABLE_CLASS, e as createTriggerController, B as BACKDROP, j as prepareOverlay, k as setOverlayId, f as present, g as dismiss, h as eventMethod } from './overlays.js';
12
- import { g as getClassMap } from './theme.js';
13
- import { e as deepReady, w as waitForMount } from './index2.js';
14
- import { b as getIonMode } from './ionic-global.js';
15
- import { KEYBOARD_DID_OPEN } from './keyboard.js';
16
- import { c as createAnimation } from './animation.js';
17
- import { g as getTimeGivenProgression } from './cubic-bezier.js';
18
- import { createGesture } from './index3.js';
19
- import { w as win } from './index9.js';
20
- import { d as defineCustomElement$1 } from './backdrop.js';
21
-
22
- var Style;
23
- (function (Style) {
24
- Style["Dark"] = "DARK";
25
- Style["Light"] = "LIGHT";
26
- Style["Default"] = "DEFAULT";
27
- })(Style || (Style = {}));
28
- const StatusBar = {
29
- getEngine() {
30
- const capacitor = getCapacitor();
31
- if (capacitor === null || capacitor === void 0 ? void 0 : capacitor.isPluginAvailable('StatusBar')) {
32
- return capacitor.Plugins.StatusBar;
33
- }
34
- return undefined;
35
- },
36
- setStyle(options) {
37
- const engine = this.getEngine();
38
- if (!engine) {
39
- return;
40
- }
41
- engine.setStyle(options);
42
- },
43
- getStyle: async function () {
44
- const engine = this.getEngine();
45
- if (!engine) {
46
- return Style.Default;
47
- }
48
- const { style } = await engine.getInfo();
49
- return style;
50
- },
51
- };
52
-
53
- /**
54
- * Use y = mx + b to
55
- * figure out the backdrop value
56
- * at a particular x coordinate. This
57
- * is useful when the backdrop does
58
- * not begin to fade in until after
59
- * the 0 breakpoint.
60
- */
61
- const getBackdropValueForSheet = (x, backdropBreakpoint) => {
62
- /**
63
- * We will use these points:
64
- * (backdropBreakpoint, 0)
65
- * (maxBreakpoint, 1)
66
- * We know that at the beginning breakpoint,
67
- * the backdrop will be hidden. We also
68
- * know that at the maxBreakpoint, the backdrop
69
- * must be fully visible. maxBreakpoint should
70
- * always be 1 even if the maximum value
71
- * of the breakpoints array is not 1 since
72
- * the animation runs from a progress of 0
73
- * to a progress of 1.
74
- * m = (y2 - y1) / (x2 - x1)
75
- *
76
- * This is simplified from:
77
- * m = (1 - 0) / (maxBreakpoint - backdropBreakpoint)
78
- *
79
- * If the backdropBreakpoint is 1, we return 0 as the
80
- * backdrop is completely hidden.
81
- *
82
- */
83
- if (backdropBreakpoint === 1) {
84
- return 0;
85
- }
86
- const slope = 1 / (1 - backdropBreakpoint);
87
- /**
88
- * From here, compute b which is
89
- * the backdrop opacity if the offset
90
- * is 0. If the backdrop does not
91
- * begin to fade in until after the
92
- * 0 breakpoint, this b value will be
93
- * negative. This is fine as we never pass
94
- * b directly into the animation keyframes.
95
- * b = y - mx
96
- * Use a known point: (backdropBreakpoint, 0)
97
- * This is simplified from:
98
- * b = 0 - (backdropBreakpoint * slope)
99
- */
100
- const b = -(backdropBreakpoint * slope);
101
- /**
102
- * Finally, we can now determine the
103
- * backdrop offset given an arbitrary
104
- * gesture offset.
105
- */
106
- return x * slope + b;
107
- };
108
- /**
109
- * The tablet/desktop card modal activates
110
- * when the window width is >= 768.
111
- * At that point, the presenting element
112
- * is not transformed, so we do not need to
113
- * adjust the status bar color.
114
- *
115
- */
116
- const setCardStatusBarDark = () => {
117
- if (!win || win.innerWidth >= 768) {
118
- return;
119
- }
120
- StatusBar.setStyle({ style: Style.Dark });
121
- };
122
- const setCardStatusBarDefault = (defaultStyle = Style.Default) => {
123
- if (!win || win.innerWidth >= 768) {
124
- return;
125
- }
126
- StatusBar.setStyle({ style: defaultStyle });
127
- };
128
-
129
- const handleCanDismiss = async (el, animation) => {
130
- /**
131
- * If canDismiss is not a function
132
- * then we can return early. If canDismiss is `true`,
133
- * then canDismissBlocksGesture is `false` as canDismiss
134
- * will never interrupt the gesture. As a result,
135
- * this code block is never reached. If canDismiss is `false`,
136
- * then we never dismiss.
137
- */
138
- if (typeof el.canDismiss !== 'function') {
139
- return;
140
- }
141
- /**
142
- * Run the canDismiss callback.
143
- * If the function returns `true`,
144
- * then we can proceed with dismiss.
145
- */
146
- const shouldDismiss = await el.canDismiss(undefined, GESTURE);
147
- if (!shouldDismiss) {
148
- return;
149
- }
150
- /**
151
- * If canDismiss resolved after the snap
152
- * back animation finished, we can
153
- * dismiss immediately.
154
- *
155
- * If canDismiss resolved before the snap
156
- * back animation finished, we need to
157
- * wait until the snap back animation is
158
- * done before dismissing.
159
- */
160
- if (animation.isRunning()) {
161
- animation.onFinish(() => {
162
- el.dismiss(undefined, 'handler');
163
- }, { oneTimeCallback: true });
164
- }
165
- else {
166
- el.dismiss(undefined, 'handler');
167
- }
168
- };
169
- /**
170
- * This function lets us simulate a realistic spring-like animation
171
- * when swiping down on the modal.
172
- * There are two forces that we need to use to compute the spring physics:
173
- *
174
- * 1. Stiffness, k: This is a measure of resistance applied a spring.
175
- * 2. Dampening, c: This value has the effect of reducing or preventing oscillation.
176
- *
177
- * Using these two values, we can calculate the Spring Force and the Dampening Force
178
- * to compute the total force applied to a spring.
179
- *
180
- * Spring Force: This force pulls a spring back into its equilibrium position.
181
- * Hooke's Law tells us that that spring force (FS) = kX.
182
- * k is the stiffness of a spring, and X is the displacement of the spring from its
183
- * equilibrium position. In this case, it is the amount by which the free end
184
- * of a spring was displaced (stretched/pushed) from its "relaxed" position.
185
- *
186
- * Dampening Force: This force slows down motion. Without it, a spring would oscillate forever.
187
- * The dampening force, FD, can be found via this formula: FD = -cv
188
- * where c the dampening value and v is velocity.
189
- *
190
- * Therefore, the resulting force that is exerted on the block is:
191
- * F = FS + FD = -kX - cv
192
- *
193
- * Newton's 2nd Law tells us that F = ma:
194
- * ma = -kX - cv.
195
- *
196
- * For Ionic's purposes, we can assume that m = 1:
197
- * a = -kX - cv
198
- *
199
- * Imagine a block attached to the end of a spring. At equilibrium
200
- * the block is at position x = 1.
201
- * Pressing on the block moves it to position x = 0;
202
- * So, to calculate the displacement, we need to take the
203
- * current position and subtract the previous position from it.
204
- * X = x - x0 = 0 - 1 = -1.
205
- *
206
- * For Ionic's purposes, we are only pushing on the spring modal
207
- * so we have a max position of 1.
208
- * As a result, we can expand displacement to this formula:
209
- * X = x - 1
210
- *
211
- * a = -k(x - 1) - cv
212
- *
213
- * We can represent the motion of something as a function of time: f(t) = x.
214
- * The derivative of position gives us the velocity: f'(t)
215
- * The derivative of the velocity gives us the acceleration: f''(t)
216
- *
217
- * We can substitute the formula above with these values:
218
- *
219
- * f"(t) = -k * (f(t) - 1) - c * f'(t)
220
- *
221
- * This is called a differential equation.
222
- *
223
- * We know that at t = 0, we are at x = 0 because the modal does not move: f(0) = 0
224
- * This means our velocity is also zero: f'(0) = 0.
225
- *
226
- * We can cheat a bit and plug the formula into Wolfram Alpha.
227
- * However, we need to pick stiffness and dampening values:
228
- * k = 0.57
229
- * c = 15
230
- *
231
- * I picked these as they are fairly close to native iOS's spring effect
232
- * with the modal.
233
- *
234
- * What we plug in is this: f(0) = 0; f'(0) = 0; f''(t) = -0.57(f(t) - 1) - 15f'(t)
235
- *
236
- * The result is a formula that lets us calculate the acceleration
237
- * for a given time t.
238
- * Note: This is the approximate form of the solution. Wolfram Alpha will
239
- * give you a complex differential equation too.
240
- */
241
- const calculateSpringStep = (t) => {
242
- return 0.00255275 * 2.71828 ** (-14.9619 * t) - 1.00255 * 2.71828 ** (-0.0380968 * t) + 1;
243
- };
244
-
245
- // Defaults for the card swipe animation
246
- const SwipeToCloseDefaults = {
247
- MIN_PRESENTING_SCALE: 0.915,
248
- };
249
- const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismiss, onDragStart, onDragMove, onDragEnd) => {
250
- /**
251
- * The step value at which a card modal
252
- * is eligible for dismissing via gesture.
253
- */
254
- const DISMISS_THRESHOLD = 0.5;
255
- const height = el.offsetHeight;
256
- let isOpen = false;
257
- let canDismissBlocksGesture = false;
258
- let contentEl = null;
259
- let scrollEl = null;
260
- const canDismissMaxStep = 0.2;
261
- let initialScrollY = true;
262
- let lastStep = 0;
263
- const getScrollY = () => {
264
- if (contentEl && isIonContent(contentEl)) {
265
- return contentEl.scrollY;
266
- /**
267
- * Custom scroll containers are intended to be
268
- * used with virtual scrolling, so we assume
269
- * there is scrolling in this case.
270
- */
271
- }
272
- else {
273
- return true;
274
- }
275
- };
276
- const canStart = (detail) => {
277
- const target = detail.event.target;
278
- if (target === null || !target.closest) {
279
- return true;
280
- }
281
- /**
282
- * If we are swiping on the content,
283
- * swiping should only be possible if
284
- * the content is scrolled all the way
285
- * to the top so that we do not interfere
286
- * with scrolling.
287
- *
288
- * We cannot assume that the `ion-content`
289
- * target will remain consistent between
290
- * swipes. For example, when using
291
- * ion-nav within a card modal it is
292
- * possible to swipe, push a view, and then
293
- * swipe again. The target content will not
294
- * be the same between swipes.
295
- */
296
- contentEl = findClosestIonContent(target);
297
- if (contentEl) {
298
- /**
299
- * The card should never swipe to close
300
- * on the content with a refresher.
301
- * Note: We cannot solve this by making the
302
- * swipeToClose gesture have a higher priority
303
- * than the refresher gesture as the iOS native
304
- * refresh gesture uses a scroll listener in
305
- * addition to a gesture.
306
- *
307
- * Note: Do not use getScrollElement here
308
- * because we need this to be a synchronous
309
- * operation, and getScrollElement is
310
- * asynchronous.
311
- */
312
- if (isIonContent(contentEl)) {
313
- const root = getElementRoot(contentEl);
314
- scrollEl = root.querySelector('.inner-scroll');
315
- }
316
- else {
317
- scrollEl = contentEl;
318
- }
319
- const hasRefresherInContent = !!contentEl.querySelector('ion-refresher');
320
- return !hasRefresherInContent && scrollEl.scrollTop === 0;
321
- }
322
- /**
323
- * Card should be swipeable on all
324
- * parts of the modal except for the footer.
325
- */
326
- const footer = target.closest('ion-footer');
327
- if (footer === null) {
328
- return true;
329
- }
330
- return false;
331
- };
332
- const onStart = (detail) => {
333
- const { deltaY } = detail;
334
- /**
335
- * Get the initial scrollY value so
336
- * that we can correctly reset the scrollY
337
- * prop when the gesture ends.
338
- */
339
- initialScrollY = getScrollY();
340
- /**
341
- * If canDismiss is anything other than `true`
342
- * then users should be able to swipe down
343
- * until a threshold is hit. At that point,
344
- * the card modal should not proceed any further.
345
- * TODO (FW-937)
346
- * Remove undefined check
347
- */
348
- canDismissBlocksGesture = el.canDismiss !== undefined && el.canDismiss !== true;
349
- /**
350
- * If we are pulling down, then
351
- * it is possible we are pulling on the
352
- * content. We do not want scrolling to
353
- * happen at the same time as the gesture.
354
- */
355
- if (deltaY > 0 && contentEl) {
356
- disableContentScrollY(contentEl);
357
- }
358
- animation.progressStart(true, isOpen ? 1 : 0);
359
- onDragStart();
360
- };
361
- const onMove = (detail) => {
362
- const { deltaY } = detail;
363
- /**
364
- * If we are pulling down, then
365
- * it is possible we are pulling on the
366
- * content. We do not want scrolling to
367
- * happen at the same time as the gesture.
368
- */
369
- if (deltaY > 0 && contentEl) {
370
- disableContentScrollY(contentEl);
371
- }
372
- /**
373
- * If we are swiping on the content
374
- * then the swipe gesture should only
375
- * happen if we are pulling down.
376
- *
377
- * However, if we pull up and
378
- * then down such that the scroll position
379
- * returns to 0, we should be able to swipe
380
- * the card.
381
- */
382
- const step = detail.deltaY / height;
383
- /**
384
- * Check if user is swiping down and
385
- * if we have a canDismiss value that
386
- * should block the gesture from
387
- * proceeding,
388
- */
389
- const isAttemptingDismissWithCanDismiss = step >= 0 && canDismissBlocksGesture;
390
- /**
391
- * If we are blocking the gesture from dismissing,
392
- * set the max step value so that the sheet cannot be
393
- * completely hidden.
394
- */
395
- const maxStep = isAttemptingDismissWithCanDismiss ? canDismissMaxStep : 0.9999;
396
- /**
397
- * If we are blocking the gesture from
398
- * dismissing, calculate the spring modifier value
399
- * this will be added to the starting breakpoint
400
- * value to give the gesture a spring-like feeling.
401
- * Note that the starting breakpoint is always 0,
402
- * so we omit adding 0 to the result.
403
- */
404
- const processedStep = isAttemptingDismissWithCanDismiss ? calculateSpringStep(step / maxStep) : step;
405
- const clampedStep = clamp(0.0001, processedStep, maxStep);
406
- animation.progressStep(clampedStep);
407
- /**
408
- * When swiping down half way, the status bar style
409
- * should be reset to its default value.
410
- *
411
- * We track lastStep so that we do not fire these
412
- * functions on every onMove, only when the user has
413
- * crossed a certain threshold.
414
- */
415
- if (clampedStep >= DISMISS_THRESHOLD && lastStep < DISMISS_THRESHOLD) {
416
- setCardStatusBarDefault(statusBarStyle);
417
- /**
418
- * However, if we swipe back up, then the
419
- * status bar style should be set to have light
420
- * text on a dark background.
421
- */
422
- }
423
- else if (clampedStep < DISMISS_THRESHOLD && lastStep >= DISMISS_THRESHOLD) {
424
- setCardStatusBarDark();
425
- }
426
- lastStep = clampedStep;
427
- const eventDetail = {
428
- currentY: detail.currentY,
429
- deltaY: detail.deltaY,
430
- velocityY: detail.velocityY,
431
- progress: calculateProgress(el, detail.deltaY),
432
- };
433
- onDragMove(eventDetail);
434
- };
435
- const onEnd = (detail) => {
436
- const velocity = detail.velocityY;
437
- const step = detail.deltaY / height;
438
- const isAttemptingDismissWithCanDismiss = step >= 0 && canDismissBlocksGesture;
439
- const maxStep = isAttemptingDismissWithCanDismiss ? canDismissMaxStep : 0.9999;
440
- const processedStep = isAttemptingDismissWithCanDismiss ? calculateSpringStep(step / maxStep) : step;
441
- const clampedStep = clamp(0.0001, processedStep, maxStep);
442
- const threshold = (detail.deltaY + velocity * 1000) / height;
443
- /**
444
- * If canDismiss blocks
445
- * the swipe gesture, then the
446
- * animation can never complete until
447
- * canDismiss is checked.
448
- */
449
- const shouldComplete = !isAttemptingDismissWithCanDismiss && threshold >= DISMISS_THRESHOLD;
450
- let newStepValue = shouldComplete ? -1e-3 : 0.001;
451
- if (!shouldComplete) {
452
- animation.easing('cubic-bezier(1, 0, 0.68, 0.28)');
453
- newStepValue += getTimeGivenProgression([0, 0], [1, 0], [0.68, 0.28], [1, 1], clampedStep)[0];
454
- }
455
- else {
456
- animation.easing('cubic-bezier(0.32, 0.72, 0, 1)');
457
- newStepValue += getTimeGivenProgression([0, 0], [0.32, 0.72], [0, 1], [1, 1], clampedStep)[0];
458
- }
459
- const duration = shouldComplete
460
- ? computeDuration(step * height, velocity)
461
- : computeDuration((1 - clampedStep) * height, velocity);
462
- isOpen = shouldComplete;
463
- gesture.enable(false);
464
- if (contentEl) {
465
- resetContentScrollY(contentEl, initialScrollY);
466
- }
467
- animation
468
- .onFinish(() => {
469
- if (!shouldComplete) {
470
- gesture.enable(true);
471
- }
472
- })
473
- .progressEnd(shouldComplete ? 1 : 0, newStepValue, duration);
474
- /**
475
- * If the canDismiss value blocked the gesture
476
- * from proceeding, then we should ignore whatever
477
- * shouldComplete is. Whether or not the modal
478
- * animation should complete is now determined by
479
- * canDismiss.
480
- *
481
- * If the user swiped >25% of the way
482
- * to the max step, then we should
483
- * check canDismiss. 25% was chosen
484
- * to avoid accidental swipes.
485
- */
486
- if (isAttemptingDismissWithCanDismiss && clampedStep > maxStep / 4) {
487
- handleCanDismiss(el, animation);
488
- }
489
- else if (shouldComplete) {
490
- onDismiss();
491
- }
492
- const eventDetail = {
493
- currentY: detail.currentY,
494
- deltaY: detail.deltaY,
495
- velocityY: detail.velocityY,
496
- progress: calculateProgress(el, detail.deltaY),
497
- };
498
- onDragEnd(eventDetail);
499
- };
500
- const gesture = createGesture({
501
- el,
502
- gestureName: 'modalSwipeToClose',
503
- gesturePriority: OVERLAY_GESTURE_PRIORITY,
504
- direction: 'y',
505
- threshold: 10,
506
- canStart,
507
- onStart,
508
- onMove,
509
- onEnd,
510
- });
511
- return gesture;
512
- };
513
- const computeDuration = (remaining, velocity) => {
514
- return clamp(400, remaining / Math.abs(velocity * 1.1), 500);
515
- };
516
- /**
517
- * Calculates the progress of the swipe gesture.
518
- *
519
- * The progress is a value between 0 and 1 that represents how far
520
- * the swipe has progressed towards closing the modal.
521
- *
522
- * A value closer to 1 means the modal is closer to being opened,
523
- * while a value closer to 0 means the modal is closer to being closed.
524
- *
525
- * @param el The modal
526
- * @param deltaY The change in Y position (positive when dragging down, negative when dragging up)
527
- * @returns The progress of the swipe gesture
528
- */
529
- const calculateProgress = (el, deltaY) => {
530
- const windowHeight = window.innerHeight;
531
- // Position when fully open
532
- const modalTop = el.getBoundingClientRect().top;
533
- /**
534
- * The distance between the top of the modal and the bottom of the screen
535
- * is the total distance the modal needs to travel to be fully closed.
536
- */
537
- const totalDistance = windowHeight - modalTop;
538
- /**
539
- * The pull percentage is how far the user has swiped compared to the total
540
- * distance needed to close the modal.
541
- */
542
- const pullPercentage = deltaY / totalDistance;
543
- /**
544
- * The progress is the inverse of the pull percentage because
545
- * when the user starts swiping up, the progress should be close to 1,
546
- * and when the user has swiped all the way down, the progress should be
547
- * close to 0.
548
- */
549
- const progress = 1 - pullPercentage;
550
- // Round to the nearest thousandth to avoid returning very small decimal
551
- const roundedProgress = Math.round(progress * 1000) / 1000;
552
- return Math.max(0, Math.min(1, roundedProgress));
553
- };
554
-
555
- const createSheetEnterAnimation = (opts) => {
556
- const { currentBreakpoint, backdropBreakpoint, expandToScroll } = opts;
557
- /**
558
- * If the backdropBreakpoint is undefined, then the backdrop
559
- * should always fade in. If the backdropBreakpoint came before the
560
- * current breakpoint, then the backdrop should be fading in.
561
- */
562
- const shouldShowBackdrop = backdropBreakpoint === undefined || backdropBreakpoint < currentBreakpoint;
563
- const initialBackdrop = shouldShowBackdrop ? `calc(var(--backdrop-opacity) * ${currentBreakpoint})` : '0';
564
- const backdropAnimation = createAnimation('backdropAnimation').fromTo('opacity', 0, initialBackdrop);
565
- if (shouldShowBackdrop) {
566
- backdropAnimation
567
- .beforeStyles({
568
- 'pointer-events': 'none',
569
- })
570
- .afterClearStyles(['pointer-events']);
571
- }
572
- const wrapperAnimation = createAnimation('wrapperAnimation').keyframes([
573
- { offset: 0, opacity: 1, transform: 'translateY(100%)' },
574
- { offset: 1, opacity: 1, transform: `translateY(${100 - currentBreakpoint * 100}%)` },
575
- ]);
576
- /**
577
- * This allows the content to be scrollable at any breakpoint.
578
- */
579
- const contentAnimation = !expandToScroll
580
- ? createAnimation('contentAnimation').keyframes([
581
- { offset: 0, opacity: 1, maxHeight: `${(1 - currentBreakpoint) * 100}%` },
582
- { offset: 1, opacity: 1, maxHeight: `${currentBreakpoint * 100}%` },
583
- ])
584
- : undefined;
585
- return { wrapperAnimation, backdropAnimation, contentAnimation };
586
- };
587
- const createSheetLeaveAnimation = (opts) => {
588
- const { currentBreakpoint, backdropBreakpoint } = opts;
589
- /**
590
- * Backdrop does not always fade in from 0 to 1 if backdropBreakpoint
591
- * is defined, so we need to account for that offset by figuring out
592
- * what the current backdrop value should be.
593
- */
594
- const backdropValue = `calc(var(--backdrop-opacity) * ${getBackdropValueForSheet(currentBreakpoint, backdropBreakpoint)})`;
595
- const defaultBackdrop = [
596
- { offset: 0, opacity: backdropValue },
597
- { offset: 1, opacity: 0 },
598
- ];
599
- const customBackdrop = [
600
- { offset: 0, opacity: backdropValue },
601
- { offset: backdropBreakpoint, opacity: 0 },
602
- { offset: 1, opacity: 0 },
603
- ];
604
- const backdropAnimation = createAnimation('backdropAnimation').keyframes(backdropBreakpoint !== 0 ? customBackdrop : defaultBackdrop);
605
- const wrapperAnimation = createAnimation('wrapperAnimation').keyframes([
606
- { offset: 0, opacity: 1, transform: `translateY(${100 - currentBreakpoint * 100}%)` },
607
- { offset: 1, opacity: 1, transform: `translateY(100%)` },
608
- ]);
609
- return { wrapperAnimation, backdropAnimation };
610
- };
611
-
612
- const createEnterAnimation$1 = () => {
613
- const backdropAnimation = createAnimation()
614
- .fromTo('opacity', 0.01, 'var(--backdrop-opacity)')
615
- .beforeStyles({
616
- 'pointer-events': 'none',
617
- })
618
- .afterClearStyles(['pointer-events']);
619
- const wrapperAnimation = createAnimation().fromTo('transform', 'translateY(100vh)', 'translateY(0vh)');
620
- return { backdropAnimation, wrapperAnimation, contentAnimation: undefined };
621
- };
622
- /**
623
- * iOS Modal Enter Animation for the Card presentation style
624
- */
625
- const iosEnterAnimation = (baseEl, opts) => {
626
- const { presentingEl, currentBreakpoint, expandToScroll } = opts;
627
- const root = getElementRoot(baseEl);
628
- const { wrapperAnimation, backdropAnimation, contentAnimation } = currentBreakpoint !== undefined ? createSheetEnterAnimation(opts) : createEnterAnimation$1();
629
- backdropAnimation.addElement(root.querySelector('ion-backdrop'));
630
- wrapperAnimation.addElement(root.querySelectorAll('.modal-wrapper, .modal-shadow')).beforeStyles({ opacity: 1 });
631
- // The content animation is only added if scrolling is enabled for
632
- // all the breakpoints.
633
- !expandToScroll && (contentAnimation === null || contentAnimation === void 0 ? void 0 : contentAnimation.addElement(baseEl.querySelector('.ion-page')));
634
- const baseAnimation = createAnimation('entering-base')
635
- .addElement(baseEl)
636
- .easing('cubic-bezier(0.32,0.72,0,1)')
637
- .duration(500)
638
- .addAnimation([wrapperAnimation]);
639
- if (contentAnimation) {
640
- baseAnimation.addAnimation(contentAnimation);
641
- }
642
- if (presentingEl) {
643
- const isPortrait = window.innerWidth < 768;
644
- const hasCardModal = presentingEl.tagName === 'ION-MODAL' && presentingEl.presentingElement !== undefined;
645
- const presentingElRoot = getElementRoot(presentingEl);
646
- const presentingAnimation = createAnimation().beforeStyles({
647
- transform: 'translateY(0)',
648
- 'transform-origin': 'top center',
649
- overflow: 'hidden',
650
- });
651
- const bodyEl = document.body;
652
- if (isPortrait) {
653
- /**
654
- * Fallback for browsers that does not support `max()` (ex: Firefox)
655
- * No need to worry about statusbar padding since engines like Gecko
656
- * are not used as the engine for standalone Cordova/Capacitor apps
657
- */
658
- const transformOffset = !CSS.supports('width', 'max(0px, 1px)') ? '30px' : 'max(30px, var(--ion-safe-area-top))';
659
- const modalTransform = hasCardModal ? '-10px' : transformOffset;
660
- const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
661
- const finalTransform = `translateY(${modalTransform}) scale(${toPresentingScale})`;
662
- presentingAnimation
663
- .afterStyles({
664
- transform: finalTransform,
665
- })
666
- .beforeAddWrite(() => bodyEl.style.setProperty('background-color', 'black'))
667
- .addElement(presentingEl)
668
- .keyframes([
669
- { offset: 0, filter: 'contrast(1)', transform: 'translateY(0px) scale(1)', borderRadius: '0px' },
670
- { offset: 1, filter: 'contrast(0.85)', transform: finalTransform, borderRadius: '10px 10px 0 0' },
671
- ]);
672
- baseAnimation.addAnimation(presentingAnimation);
673
- }
674
- else {
675
- baseAnimation.addAnimation(backdropAnimation);
676
- if (!hasCardModal) {
677
- wrapperAnimation.fromTo('opacity', '0', '1');
678
- }
679
- else {
680
- const toPresentingScale = hasCardModal ? SwipeToCloseDefaults.MIN_PRESENTING_SCALE : 1;
681
- const finalTransform = `translateY(-10px) scale(${toPresentingScale})`;
682
- presentingAnimation
683
- .afterStyles({
684
- transform: finalTransform,
685
- })
686
- .addElement(presentingElRoot.querySelector('.modal-wrapper'))
687
- .keyframes([
688
- { offset: 0, filter: 'contrast(1)', transform: 'translateY(0) scale(1)' },
689
- { offset: 1, filter: 'contrast(0.85)', transform: finalTransform },
690
- ]);
691
- const shadowAnimation = createAnimation()
692
- .afterStyles({
693
- transform: finalTransform,
694
- })
695
- .addElement(presentingElRoot.querySelector('.modal-shadow'))
696
- .keyframes([
697
- { offset: 0, opacity: '1', transform: 'translateY(0) scale(1)' },
698
- { offset: 1, opacity: '0', transform: finalTransform },
699
- ]);
700
- baseAnimation.addAnimation([presentingAnimation, shadowAnimation]);
701
- }
702
- }
703
- }
704
- else {
705
- baseAnimation.addAnimation(backdropAnimation);
706
- }
707
- return baseAnimation;
708
- };
709
-
710
- const createLeaveAnimation$1 = () => {
711
- const backdropAnimation = createAnimation().fromTo('opacity', 'var(--backdrop-opacity)', 0);
712
- const wrapperAnimation = createAnimation().fromTo('transform', 'translateY(0vh)', 'translateY(100vh)');
713
- return { backdropAnimation, wrapperAnimation };
714
- };
715
- /**
716
- * iOS Modal Leave Animation
717
- */
718
- const iosLeaveAnimation = (baseEl, opts, duration = 500) => {
719
- const { presentingEl, currentBreakpoint } = opts;
720
- const root = getElementRoot(baseEl);
721
- const { wrapperAnimation, backdropAnimation } = currentBreakpoint !== undefined ? createSheetLeaveAnimation(opts) : createLeaveAnimation$1();
722
- backdropAnimation.addElement(root.querySelector('ion-backdrop'));
723
- wrapperAnimation.addElement(root.querySelectorAll('.modal-wrapper, .modal-shadow')).beforeStyles({ opacity: 1 });
724
- const baseAnimation = createAnimation('leaving-base')
725
- .addElement(baseEl)
726
- .easing('cubic-bezier(0.32,0.72,0,1)')
727
- .duration(duration)
728
- .addAnimation(wrapperAnimation);
729
- if (presentingEl) {
730
- const isPortrait = window.innerWidth < 768;
731
- const hasCardModal = presentingEl.tagName === 'ION-MODAL' && presentingEl.presentingElement !== undefined;
732
- const presentingElRoot = getElementRoot(presentingEl);
733
- const presentingAnimation = createAnimation()
734
- .beforeClearStyles(['transform'])
735
- .afterClearStyles(['transform'])
736
- .onFinish((currentStep) => {
737
- // only reset background color if this is the last card-style modal
738
- if (currentStep !== 1) {
739
- return;
740
- }
741
- presentingEl.style.setProperty('overflow', '');
742
- const numModals = Array.from(bodyEl.querySelectorAll('ion-modal:not(.overlay-hidden)')).filter((m) => m.presentingElement !== undefined).length;
743
- if (numModals <= 1) {
744
- bodyEl.style.setProperty('background-color', '');
745
- }
746
- });
747
- const bodyEl = document.body;
748
- if (isPortrait) {
749
- const transformOffset = !CSS.supports('width', 'max(0px, 1px)') ? '30px' : 'max(30px, var(--ion-safe-area-top))';
750
- const modalTransform = hasCardModal ? '-10px' : transformOffset;
751
- const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
752
- const finalTransform = `translateY(${modalTransform}) scale(${toPresentingScale})`;
753
- presentingAnimation.addElement(presentingEl).keyframes([
754
- { offset: 0, filter: 'contrast(0.85)', transform: finalTransform, borderRadius: '10px 10px 0 0' },
755
- { offset: 1, filter: 'contrast(1)', transform: 'translateY(0px) scale(1)', borderRadius: '0px' },
756
- ]);
757
- baseAnimation.addAnimation(presentingAnimation);
758
- }
759
- else {
760
- baseAnimation.addAnimation(backdropAnimation);
761
- if (!hasCardModal) {
762
- wrapperAnimation.fromTo('opacity', '1', '0');
763
- }
764
- else {
765
- const toPresentingScale = hasCardModal ? SwipeToCloseDefaults.MIN_PRESENTING_SCALE : 1;
766
- const finalTransform = `translateY(-10px) scale(${toPresentingScale})`;
767
- presentingAnimation
768
- .addElement(presentingElRoot.querySelector('.modal-wrapper'))
769
- .afterStyles({
770
- transform: 'translate3d(0, 0, 0)',
771
- })
772
- .keyframes([
773
- { offset: 0, filter: 'contrast(0.85)', transform: finalTransform },
774
- { offset: 1, filter: 'contrast(1)', transform: 'translateY(0) scale(1)' },
775
- ]);
776
- const shadowAnimation = createAnimation()
777
- .addElement(presentingElRoot.querySelector('.modal-shadow'))
778
- .afterStyles({
779
- transform: 'translateY(0) scale(1)',
780
- })
781
- .keyframes([
782
- { offset: 0, opacity: '0', transform: finalTransform },
783
- { offset: 1, opacity: '1', transform: 'translateY(0) scale(1)' },
784
- ]);
785
- baseAnimation.addAnimation([presentingAnimation, shadowAnimation]);
786
- }
787
- }
788
- }
789
- else {
790
- baseAnimation.addAnimation(backdropAnimation);
791
- }
792
- return baseAnimation;
793
- };
794
-
795
- /**
796
- * Transition animation from portrait view to landscape view
797
- * This handles the case where a card modal is open in portrait view
798
- * and the user switches to landscape view
799
- */
800
- const portraitToLandscapeTransition = (baseEl, opts, duration = 300) => {
801
- const { presentingEl } = opts;
802
- if (!presentingEl) {
803
- // No transition needed for non-card modals
804
- return createAnimation('portrait-to-landscape-transition');
805
- }
806
- const presentingElIsCardModal = presentingEl.tagName === 'ION-MODAL' && presentingEl.presentingElement !== undefined;
807
- const presentingElRoot = getElementRoot(presentingEl);
808
- const bodyEl = document.body;
809
- const baseAnimation = createAnimation('portrait-to-landscape-transition')
810
- .addElement(baseEl)
811
- .easing('cubic-bezier(0.32,0.72,0,1)')
812
- .duration(duration);
813
- const presentingAnimation = createAnimation().beforeStyles({
814
- transform: 'translateY(0)',
815
- 'transform-origin': 'top center',
816
- overflow: 'hidden',
817
- });
818
- if (!presentingElIsCardModal) {
819
- // The presenting element is not a card modal, so we do not
820
- // need to care about layering and modal-specific styles.
821
- const root = getElementRoot(baseEl);
822
- const wrapperAnimation = createAnimation()
823
- .addElement(root.querySelectorAll('.modal-wrapper, .modal-shadow'))
824
- .fromTo('opacity', '1', '1'); // Keep wrapper visible in landscape
825
- const backdropAnimation = createAnimation()
826
- .addElement(root.querySelector('ion-backdrop'))
827
- .fromTo('opacity', 'var(--backdrop-opacity)', 'var(--backdrop-opacity)'); // Keep backdrop visible
828
- // Animate presentingEl from portrait state back to normal
829
- const transformOffset = !CSS.supports('width', 'max(0px, 1px)') ? '30px' : 'max(30px, var(--ion-safe-area-top))';
830
- const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
831
- const fromTransform = `translateY(${transformOffset}) scale(${toPresentingScale})`;
832
- presentingAnimation
833
- .addElement(presentingEl)
834
- .afterStyles({
835
- transform: 'translateY(0px) scale(1)',
836
- 'border-radius': '0px',
837
- })
838
- .beforeAddWrite(() => bodyEl.style.setProperty('background-color', ''))
839
- .fromTo('transform', fromTransform, 'translateY(0px) scale(1)')
840
- .fromTo('filter', 'contrast(0.85)', 'contrast(1)')
841
- .fromTo('border-radius', '10px 10px 0 0', '0px');
842
- baseAnimation.addAnimation([presentingAnimation, wrapperAnimation, backdropAnimation]);
843
- }
844
- else {
845
- // The presenting element is a card modal, so we do
846
- // need to care about layering and modal-specific styles.
847
- const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
848
- const fromTransform = `translateY(-10px) scale(${toPresentingScale})`;
849
- const toTransform = `translateY(0px) scale(1)`;
850
- presentingAnimation
851
- .addElement(presentingEl)
852
- .afterStyles({
853
- transform: toTransform,
854
- })
855
- .fromTo('transform', fromTransform, toTransform)
856
- .fromTo('filter', 'contrast(0.85)', 'contrast(1)');
857
- const shadowAnimation = createAnimation()
858
- .addElement(presentingElRoot.querySelector('.modal-shadow'))
859
- .afterStyles({
860
- transform: toTransform,
861
- opacity: '0',
862
- })
863
- .fromTo('transform', fromTransform, toTransform);
864
- baseAnimation.addAnimation([presentingAnimation, shadowAnimation]);
865
- }
866
- return baseAnimation;
867
- };
868
- /**
869
- * Transition animation from landscape view to portrait view
870
- * This handles the case where a card modal is open in landscape view
871
- * and the user switches to portrait view
872
- */
873
- const landscapeToPortraitTransition = (baseEl, opts, duration = 300) => {
874
- const { presentingEl } = opts;
875
- if (!presentingEl) {
876
- // No transition needed for non-card modals
877
- return createAnimation('landscape-to-portrait-transition');
878
- }
879
- const presentingElIsCardModal = presentingEl.tagName === 'ION-MODAL' && presentingEl.presentingElement !== undefined;
880
- const presentingElRoot = getElementRoot(presentingEl);
881
- const bodyEl = document.body;
882
- const baseAnimation = createAnimation('landscape-to-portrait-transition')
883
- .addElement(baseEl)
884
- .easing('cubic-bezier(0.32,0.72,0,1)')
885
- .duration(duration);
886
- const presentingAnimation = createAnimation().beforeStyles({
887
- transform: 'translateY(0)',
888
- 'transform-origin': 'top center',
889
- overflow: 'hidden',
890
- });
891
- if (!presentingElIsCardModal) {
892
- // The presenting element is not a card modal, so we do not
893
- // need to care about layering and modal-specific styles.
894
- const root = getElementRoot(baseEl);
895
- const wrapperAnimation = createAnimation()
896
- .addElement(root.querySelectorAll('.modal-wrapper, .modal-shadow'))
897
- .fromTo('opacity', '1', '1'); // Keep wrapper visible
898
- const backdropAnimation = createAnimation()
899
- .addElement(root.querySelector('ion-backdrop'))
900
- .fromTo('opacity', 'var(--backdrop-opacity)', 'var(--backdrop-opacity)'); // Keep backdrop visible
901
- // Animate presentingEl from normal state to portrait state
902
- const transformOffset = !CSS.supports('width', 'max(0px, 1px)') ? '30px' : 'max(30px, var(--ion-safe-area-top))';
903
- const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
904
- const toTransform = `translateY(${transformOffset}) scale(${toPresentingScale})`;
905
- presentingAnimation
906
- .addElement(presentingEl)
907
- .afterStyles({
908
- transform: toTransform,
909
- })
910
- .beforeAddWrite(() => bodyEl.style.setProperty('background-color', 'black'))
911
- .keyframes([
912
- { offset: 0, transform: 'translateY(0px) scale(1)', filter: 'contrast(1)', borderRadius: '0px' },
913
- { offset: 0.2, transform: 'translateY(0px) scale(1)', filter: 'contrast(1)', borderRadius: '10px 10px 0 0' },
914
- { offset: 1, transform: toTransform, filter: 'contrast(0.85)', borderRadius: '10px 10px 0 0' },
915
- ]);
916
- baseAnimation.addAnimation([presentingAnimation, wrapperAnimation, backdropAnimation]);
917
- }
918
- else {
919
- // The presenting element is also a card modal, so we need
920
- // to handle layering and modal-specific styles.
921
- const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
922
- const fromTransform = `translateY(-10px) scale(${toPresentingScale})`;
923
- const toTransform = `translateY(0) scale(1)`;
924
- presentingAnimation
925
- .addElement(presentingEl)
926
- .afterStyles({
927
- transform: toTransform,
928
- })
929
- .fromTo('transform', fromTransform, toTransform);
930
- const shadowAnimation = createAnimation()
931
- .addElement(presentingElRoot.querySelector('.modal-shadow'))
932
- .afterStyles({
933
- transform: toTransform,
934
- opacity: '0',
935
- })
936
- .fromTo('transform', fromTransform, toTransform);
937
- baseAnimation.addAnimation([presentingAnimation, shadowAnimation]);
938
- }
939
- return baseAnimation;
940
- };
941
-
942
- const createEnterAnimation = () => {
943
- const backdropAnimation = createAnimation()
944
- .fromTo('opacity', 0.01, 'var(--backdrop-opacity)')
945
- .beforeStyles({
946
- 'pointer-events': 'none',
947
- })
948
- .afterClearStyles(['pointer-events']);
949
- const wrapperAnimation = createAnimation().keyframes([
950
- { offset: 0, opacity: 0.01, transform: 'translateY(40px)' },
951
- { offset: 1, opacity: 1, transform: `translateY(0px)` },
952
- ]);
953
- return { backdropAnimation, wrapperAnimation, contentAnimation: undefined };
954
- };
955
- /**
956
- * Md Modal Enter Animation
957
- */
958
- const mdEnterAnimation = (baseEl, opts) => {
959
- const { currentBreakpoint, expandToScroll } = opts;
960
- const root = getElementRoot(baseEl);
961
- const { wrapperAnimation, backdropAnimation, contentAnimation } = currentBreakpoint !== undefined ? createSheetEnterAnimation(opts) : createEnterAnimation();
962
- backdropAnimation.addElement(root.querySelector('ion-backdrop'));
963
- wrapperAnimation.addElement(root.querySelector('.modal-wrapper'));
964
- // The content animation is only added if scrolling is enabled for
965
- // all the breakpoints.
966
- !expandToScroll && (contentAnimation === null || contentAnimation === void 0 ? void 0 : contentAnimation.addElement(baseEl.querySelector('.ion-page')));
967
- const baseAnimation = createAnimation()
968
- .addElement(baseEl)
969
- .easing('cubic-bezier(0.36,0.66,0.04,1)')
970
- .duration(280)
971
- .addAnimation([backdropAnimation, wrapperAnimation]);
972
- if (contentAnimation) {
973
- baseAnimation.addAnimation(contentAnimation);
974
- }
975
- return baseAnimation;
976
- };
977
-
978
- const createLeaveAnimation = () => {
979
- const backdropAnimation = createAnimation().fromTo('opacity', 'var(--backdrop-opacity)', 0);
980
- const wrapperAnimation = createAnimation().keyframes([
981
- { offset: 0, opacity: 0.99, transform: `translateY(0px)` },
982
- { offset: 1, opacity: 0, transform: 'translateY(40px)' },
983
- ]);
984
- return { backdropAnimation, wrapperAnimation };
985
- };
986
- /**
987
- * Md Modal Leave Animation
988
- */
989
- const mdLeaveAnimation = (baseEl, opts) => {
990
- const { currentBreakpoint } = opts;
991
- const root = getElementRoot(baseEl);
992
- const { wrapperAnimation, backdropAnimation } = currentBreakpoint !== undefined ? createSheetLeaveAnimation(opts) : createLeaveAnimation();
993
- backdropAnimation.addElement(root.querySelector('ion-backdrop'));
994
- wrapperAnimation.addElement(root.querySelector('.modal-wrapper'));
995
- const baseAnimation = createAnimation()
996
- .easing('cubic-bezier(0.47,0,0.745,0.715)')
997
- .duration(200)
998
- .addAnimation([backdropAnimation, wrapperAnimation]);
999
- return baseAnimation;
1000
- };
1001
-
1002
- const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, backdropBreakpoint, animation, breakpoints = [], expandToScroll, getCurrentBreakpoint, onDismiss, onBreakpointChange, onDragStart, onDragMove, onDragEnd) => {
1003
- // Defaults for the sheet swipe animation
1004
- const defaultBackdrop = [
1005
- { offset: 0, opacity: 'var(--backdrop-opacity)' },
1006
- { offset: 1, opacity: 0.01 },
1007
- ];
1008
- const customBackdrop = [
1009
- { offset: 0, opacity: 'var(--backdrop-opacity)' },
1010
- { offset: 1 - backdropBreakpoint, opacity: 0 },
1011
- { offset: 1, opacity: 0 },
1012
- ];
1013
- const SheetDefaults = {
1014
- WRAPPER_KEYFRAMES: [
1015
- { offset: 0, transform: 'translateY(0%)' },
1016
- { offset: 1, transform: 'translateY(100%)' },
1017
- ],
1018
- BACKDROP_KEYFRAMES: backdropBreakpoint !== 0 ? customBackdrop : defaultBackdrop,
1019
- CONTENT_KEYFRAMES: [
1020
- { offset: 0, maxHeight: '100%' },
1021
- { offset: 1, maxHeight: '0%' },
1022
- ],
1023
- };
1024
- const contentEl = baseEl.querySelector('ion-content');
1025
- const height = wrapperEl.clientHeight;
1026
- let currentBreakpoint = initialBreakpoint;
1027
- let offset = 0;
1028
- let canDismissBlocksGesture = false;
1029
- let cachedScrollEl = null;
1030
- let cachedFooterEls = null;
1031
- let cachedFooterYPosition = null;
1032
- let currentFooterState = null;
1033
- const canDismissMaxStep = 0.95;
1034
- const maxBreakpoint = breakpoints[breakpoints.length - 1];
1035
- const minBreakpoint = breakpoints[0];
1036
- const wrapperAnimation = animation.childAnimations.find((ani) => ani.id === 'wrapperAnimation');
1037
- const backdropAnimation = animation.childAnimations.find((ani) => ani.id === 'backdropAnimation');
1038
- const contentAnimation = animation.childAnimations.find((ani) => ani.id === 'contentAnimation');
1039
- const enableBackdrop = () => {
1040
- // Respect explicit opt-out of focus trapping/backdrop interactions
1041
- // If focusTrap is false or showBackdrop is false, do not enable the backdrop or re-enable focus trap
1042
- const el = baseEl;
1043
- if (el.focusTrap === false || el.showBackdrop === false) {
1044
- return;
1045
- }
1046
- baseEl.style.setProperty('pointer-events', 'auto');
1047
- backdropEl.style.setProperty('pointer-events', 'auto');
1048
- /**
1049
- * When the backdrop is enabled, elements such
1050
- * as inputs should not be focusable outside
1051
- * the sheet.
1052
- */
1053
- baseEl.classList.remove(FOCUS_TRAP_DISABLE_CLASS);
1054
- };
1055
- const disableBackdrop = () => {
1056
- baseEl.style.setProperty('pointer-events', 'none');
1057
- backdropEl.style.setProperty('pointer-events', 'none');
1058
- /**
1059
- * When the backdrop is enabled, elements such
1060
- * as inputs should not be focusable outside
1061
- * the sheet.
1062
- * Adding this class disables focus trapping
1063
- * for the sheet temporarily.
1064
- */
1065
- baseEl.classList.add(FOCUS_TRAP_DISABLE_CLASS);
1066
- };
1067
- /**
1068
- * Toggles the footer to an absolute position while moving to prevent
1069
- * it from shaking while the sheet is being dragged.
1070
- * @param newPosition Whether the footer is in a moving or stationary position.
1071
- */
1072
- const swapFooterPosition = (newPosition) => {
1073
- if (!cachedFooterEls) {
1074
- cachedFooterEls = Array.from(baseEl.querySelectorAll('ion-footer'));
1075
- if (!cachedFooterEls.length) {
1076
- return;
1077
- }
1078
- }
1079
- const page = baseEl.querySelector('.ion-page');
1080
- currentFooterState = newPosition;
1081
- if (newPosition === 'stationary') {
1082
- cachedFooterEls.forEach((cachedFooterEl) => {
1083
- // Reset positioning styles to allow normal document flow
1084
- cachedFooterEl.classList.remove('modal-footer-moving');
1085
- cachedFooterEl.style.removeProperty('position');
1086
- cachedFooterEl.style.removeProperty('width');
1087
- cachedFooterEl.style.removeProperty('height');
1088
- cachedFooterEl.style.removeProperty('top');
1089
- cachedFooterEl.style.removeProperty('left');
1090
- page === null || page === void 0 ? void 0 : page.style.removeProperty('padding-bottom');
1091
- // Move to page
1092
- page === null || page === void 0 ? void 0 : page.appendChild(cachedFooterEl);
1093
- });
1094
- }
1095
- else {
1096
- let footerHeights = 0;
1097
- cachedFooterEls.forEach((cachedFooterEl, index) => {
1098
- // Get both the footer and document body positions
1099
- const cachedFooterElRect = cachedFooterEl.getBoundingClientRect();
1100
- const bodyRect = document.body.getBoundingClientRect();
1101
- // Calculate the total height of all footers
1102
- // so we can add padding to the page element
1103
- footerHeights += cachedFooterEl.clientHeight;
1104
- // Calculate absolute position relative to body
1105
- // We need to subtract the body's offsetTop to get true position within document.body
1106
- const absoluteTop = cachedFooterElRect.top - bodyRect.top;
1107
- const absoluteLeft = cachedFooterElRect.left - bodyRect.left;
1108
- // Capture the footer's current dimensions and store them in CSS variables for
1109
- // later use when applying absolute positioning.
1110
- cachedFooterEl.style.setProperty('--pinned-width', `${cachedFooterEl.clientWidth}px`);
1111
- cachedFooterEl.style.setProperty('--pinned-height', `${cachedFooterEl.clientHeight}px`);
1112
- cachedFooterEl.style.setProperty('--pinned-top', `${absoluteTop}px`);
1113
- cachedFooterEl.style.setProperty('--pinned-left', `${absoluteLeft}px`);
1114
- // Only cache the first footer's Y position
1115
- // This is used to determine if the sheet has been moved below the footer
1116
- // and needs to be swapped back to stationary so it collapses correctly.
1117
- if (index === 0) {
1118
- cachedFooterYPosition = absoluteTop;
1119
- // If there's a header, we need to combine the header height with the footer position
1120
- // because the header moves with the drag handle, so when it starts overlapping the footer,
1121
- // we need to account for that.
1122
- const header = baseEl.querySelector('ion-header');
1123
- if (header) {
1124
- cachedFooterYPosition -= header.clientHeight;
1125
- }
1126
- }
1127
- });
1128
- // Apply the pinning of styles after we've calculated everything
1129
- // so that we don't cause layouts to shift while calculating the footer positions.
1130
- // Otherwise, with multiple footers we'll end up capturing the wrong positions.
1131
- cachedFooterEls.forEach((cachedFooterEl) => {
1132
- // Add padding to the parent element to prevent content from being hidden
1133
- // when the footer is positioned absolutely. This has to be done before we
1134
- // make the footer absolutely positioned or we may accidentally cause the
1135
- // sheet to scroll.
1136
- page === null || page === void 0 ? void 0 : page.style.setProperty('padding-bottom', `${footerHeights}px`);
1137
- // Apply positioning styles to keep footer at bottom
1138
- cachedFooterEl.classList.add('modal-footer-moving');
1139
- // Apply our preserved styles to pin the footer
1140
- cachedFooterEl.style.setProperty('position', 'absolute');
1141
- cachedFooterEl.style.setProperty('width', 'var(--pinned-width)');
1142
- cachedFooterEl.style.setProperty('height', 'var(--pinned-height)');
1143
- cachedFooterEl.style.setProperty('top', 'var(--pinned-top)');
1144
- cachedFooterEl.style.setProperty('left', 'var(--pinned-left)');
1145
- // Move the element to the body when everything else is done
1146
- document.body.appendChild(cachedFooterEl);
1147
- });
1148
- }
1149
- };
1150
- /**
1151
- * After the entering animation completes,
1152
- * we need to set the animation to go from
1153
- * offset 0 to offset 1 so that users can
1154
- * swipe in any direction. We then set the
1155
- * animation offset to the current breakpoint
1156
- * so there is no flickering.
1157
- */
1158
- if (wrapperAnimation && backdropAnimation) {
1159
- wrapperAnimation.keyframes([...SheetDefaults.WRAPPER_KEYFRAMES]);
1160
- backdropAnimation.keyframes([...SheetDefaults.BACKDROP_KEYFRAMES]);
1161
- contentAnimation === null || contentAnimation === void 0 ? void 0 : contentAnimation.keyframes([...SheetDefaults.CONTENT_KEYFRAMES]);
1162
- animation.progressStart(true, 1 - currentBreakpoint);
1163
- /**
1164
- * If backdrop is not enabled, then content
1165
- * behind modal should be clickable. To do this, we need
1166
- * to remove pointer-events from ion-modal as a whole.
1167
- * ion-backdrop and .modal-wrapper always have pointer-events: auto
1168
- * applied, so the modal content can still be interacted with.
1169
- */
1170
- const shouldEnableBackdrop = currentBreakpoint > backdropBreakpoint &&
1171
- baseEl.focusTrap !== false &&
1172
- baseEl.showBackdrop !== false;
1173
- if (shouldEnableBackdrop) {
1174
- enableBackdrop();
1175
- }
1176
- else {
1177
- disableBackdrop();
1178
- }
1179
- }
1180
- if (contentEl && currentBreakpoint !== maxBreakpoint && expandToScroll) {
1181
- contentEl.scrollY = false;
1182
- }
1183
- const canStart = (detail) => {
1184
- /**
1185
- * If we are swiping on the content, swiping should only be possible if the content
1186
- * is scrolled all the way to the top so that we do not interfere with scrolling.
1187
- *
1188
- * We cannot assume that the `ion-content` target will remain consistent between swipes.
1189
- * For example, when using ion-nav within a modal it is possible to swipe, push a view,
1190
- * and then swipe again. The target content will not be the same between swipes.
1191
- */
1192
- const contentEl = findClosestIonContent(detail.event.target);
1193
- currentBreakpoint = getCurrentBreakpoint();
1194
- /**
1195
- * If `expandToScroll` is disabled, we should not allow the swipe gesture
1196
- * to start if the content is not scrolled to the top.
1197
- */
1198
- if (!expandToScroll && contentEl) {
1199
- const scrollEl = isIonContent(contentEl) ? getElementRoot(contentEl).querySelector('.inner-scroll') : contentEl;
1200
- return scrollEl.scrollTop === 0;
1201
- }
1202
- if (currentBreakpoint === 1 && contentEl) {
1203
- /**
1204
- * The modal should never swipe to close on the content with a refresher.
1205
- * Note 1: We cannot solve this by making this gesture have a higher priority than
1206
- * the refresher gesture as the iOS native refresh gesture uses a scroll listener in
1207
- * addition to a gesture.
1208
- *
1209
- * Note 2: Do not use getScrollElement here because we need this to be a synchronous
1210
- * operation, and getScrollElement is asynchronous.
1211
- */
1212
- const scrollEl = isIonContent(contentEl) ? getElementRoot(contentEl).querySelector('.inner-scroll') : contentEl;
1213
- const hasRefresherInContent = !!contentEl.querySelector('ion-refresher');
1214
- return !hasRefresherInContent && scrollEl.scrollTop === 0;
1215
- }
1216
- return true;
1217
- };
1218
- const onStart = (detail) => {
1219
- /**
1220
- * If canDismiss is anything other than `true`
1221
- * then users should be able to swipe down
1222
- * until a threshold is hit. At that point,
1223
- * the card modal should not proceed any further.
1224
- *
1225
- * canDismiss is never fired via gesture if there is
1226
- * no 0 breakpoint. However, it can be fired if the user
1227
- * presses Esc or the hardware back button.
1228
- * TODO (FW-937)
1229
- * Remove undefined check
1230
- */
1231
- canDismissBlocksGesture = baseEl.canDismiss !== undefined && baseEl.canDismiss !== true && minBreakpoint === 0;
1232
- /**
1233
- * Cache the scroll element reference when the gesture starts,
1234
- * this allows us to avoid querying the DOM for the target in onMove,
1235
- * which would impact performance significantly.
1236
- */
1237
- if (!expandToScroll) {
1238
- const targetEl = findClosestIonContent(detail.event.target);
1239
- cachedScrollEl =
1240
- targetEl && isIonContent(targetEl) ? getElementRoot(targetEl).querySelector('.inner-scroll') : targetEl;
1241
- }
1242
- /**
1243
- * If expandToScroll is disabled, we need to swap
1244
- * the footer position to moving so that it doesn't shake
1245
- * while the sheet is being dragged.
1246
- */
1247
- if (!expandToScroll) {
1248
- swapFooterPosition('moving');
1249
- }
1250
- /**
1251
- * If we are pulling down, then it is possible we are pulling on the content.
1252
- * We do not want scrolling to happen at the same time as the gesture.
1253
- */
1254
- if (detail.deltaY > 0 && contentEl) {
1255
- contentEl.scrollY = false;
1256
- }
1257
- raf(() => {
1258
- /**
1259
- * Dismisses the open keyboard when the sheet drag gesture is started.
1260
- * Sets the focus onto the modal element.
1261
- */
1262
- baseEl.focus();
1263
- });
1264
- animation.progressStart(true, 1 - currentBreakpoint);
1265
- onDragStart();
1266
- };
1267
- const onMove = (detail) => {
1268
- /**
1269
- * If `expandToScroll` is disabled, we need to see if we're currently below
1270
- * the footer element and the footer is in a stationary position. If so,
1271
- * we need to make the stationary the original position so that the footer
1272
- * collapses with the sheet.
1273
- */
1274
- if (!expandToScroll && cachedFooterYPosition !== null && currentFooterState !== null) {
1275
- // Check if we need to swap the footer position
1276
- if (detail.currentY >= cachedFooterYPosition && currentFooterState === 'moving') {
1277
- swapFooterPosition('stationary');
1278
- }
1279
- else if (detail.currentY < cachedFooterYPosition && currentFooterState === 'stationary') {
1280
- swapFooterPosition('moving');
1281
- }
1282
- }
1283
- /**
1284
- * If `expandToScroll` is disabled, and an upwards swipe gesture is done within
1285
- * the scrollable content, we should not allow the swipe gesture to continue.
1286
- */
1287
- if (!expandToScroll && detail.deltaY <= 0 && cachedScrollEl) {
1288
- return;
1289
- }
1290
- /**
1291
- * If we are pulling down, then it is possible we are pulling on the content.
1292
- * We do not want scrolling to happen at the same time as the gesture.
1293
- * This accounts for when the user scrolls down, scrolls all the way up, and then
1294
- * pulls down again such that the modal should start to move.
1295
- */
1296
- if (detail.deltaY > 0 && contentEl) {
1297
- contentEl.scrollY = false;
1298
- }
1299
- /**
1300
- * Given the change in gesture position on the Y axis,
1301
- * compute where the offset of the animation should be
1302
- * relative to where the user dragged.
1303
- */
1304
- const initialStep = 1 - currentBreakpoint;
1305
- const secondToLastBreakpoint = breakpoints.length > 1 ? 1 - breakpoints[1] : undefined;
1306
- const step = initialStep + detail.deltaY / height;
1307
- const isAttemptingDismissWithCanDismiss = secondToLastBreakpoint !== undefined && step >= secondToLastBreakpoint && canDismissBlocksGesture;
1308
- /**
1309
- * If we are blocking the gesture from dismissing,
1310
- * set the max step value so that the sheet cannot be
1311
- * completely hidden.
1312
- */
1313
- const maxStep = isAttemptingDismissWithCanDismiss ? canDismissMaxStep : 0.9999;
1314
- /**
1315
- * If we are blocking the gesture from
1316
- * dismissing, calculate the spring modifier value
1317
- * this will be added to the starting breakpoint
1318
- * value to give the gesture a spring-like feeling.
1319
- * Note that when isAttemptingDismissWithCanDismiss is true,
1320
- * the modifier is always added to the breakpoint that
1321
- * appears right after the 0 breakpoint.
1322
- *
1323
- * Note that this modifier is essentially the progression
1324
- * between secondToLastBreakpoint and maxStep which is
1325
- * why we subtract secondToLastBreakpoint. This lets us get
1326
- * the result as a value from 0 to 1.
1327
- */
1328
- const processedStep = isAttemptingDismissWithCanDismiss && secondToLastBreakpoint !== undefined
1329
- ? secondToLastBreakpoint +
1330
- calculateSpringStep((step - secondToLastBreakpoint) / (maxStep - secondToLastBreakpoint))
1331
- : step;
1332
- offset = clamp(0.0001, processedStep, maxStep);
1333
- animation.progressStep(offset);
1334
- const closest = calculateClosestBreakpoint(detail.velocityY, detail.deltaY);
1335
- const eventDetail = {
1336
- currentY: detail.currentY,
1337
- deltaY: detail.deltaY,
1338
- velocityY: detail.velocityY,
1339
- progress: calculateProgress(detail.currentY),
1340
- currentBreakpoint: closest,
1341
- };
1342
- onDragMove(eventDetail);
1343
- };
1344
- const onEnd = (detail) => {
1345
- /**
1346
- * If expandToScroll is disabled, we should not allow the moveSheetToBreakpoint
1347
- * function to be called if the user is trying to swipe content upwards and the content
1348
- * is not scrolled to the top.
1349
- */
1350
- if (!expandToScroll && detail.deltaY <= 0 && cachedScrollEl && cachedScrollEl.scrollTop > 0) {
1351
- /**
1352
- * If expand to scroll is disabled, we need to make sure we swap the footer position
1353
- * back to stationary so that it will collapse correctly if the modal is dismissed without
1354
- * dragging (e.g. through a dismiss button).
1355
- * This can cause issues if the user has a modal with content that can be dragged, as we'll
1356
- * swap to moving on drag and if we don't swap back here then the footer will get stuck.
1357
- */
1358
- swapFooterPosition('stationary');
1359
- return;
1360
- }
1361
- const closest = calculateClosestBreakpoint(detail.velocityY, detail.deltaY);
1362
- moveSheetToBreakpoint({
1363
- breakpoint: closest,
1364
- breakpointOffset: offset,
1365
- canDismiss: canDismissBlocksGesture,
1366
- /**
1367
- * The swipe is user-driven, so we should
1368
- * always animate when the gesture ends.
1369
- */
1370
- animated: true,
1371
- });
1372
- const eventDetail = {
1373
- currentY: detail.currentY,
1374
- deltaY: detail.deltaY,
1375
- velocityY: detail.velocityY,
1376
- progress: calculateProgress(detail.currentY),
1377
- currentBreakpoint: closest,
1378
- };
1379
- onDragEnd(eventDetail);
1380
- };
1381
- const moveSheetToBreakpoint = (options) => {
1382
- const { breakpoint, canDismiss, breakpointOffset, animated } = options;
1383
- /**
1384
- * canDismiss should only prevent snapping
1385
- * when users are trying to dismiss. If canDismiss
1386
- * is present but the user is trying to swipe upwards,
1387
- * we should allow that to happen,
1388
- */
1389
- const shouldPreventDismiss = canDismiss && breakpoint === 0;
1390
- const snapToBreakpoint = shouldPreventDismiss ? currentBreakpoint : breakpoint;
1391
- const shouldRemainOpen = snapToBreakpoint !== 0;
1392
- currentBreakpoint = 0;
1393
- /**
1394
- * Update the animation so that it plays from
1395
- * the last offset to the closest snap point.
1396
- */
1397
- if (wrapperAnimation && backdropAnimation) {
1398
- wrapperAnimation.keyframes([
1399
- { offset: 0, transform: `translateY(${breakpointOffset * 100}%)` },
1400
- { offset: 1, transform: `translateY(${(1 - snapToBreakpoint) * 100}%)` },
1401
- ]);
1402
- backdropAnimation.keyframes([
1403
- {
1404
- offset: 0,
1405
- opacity: `calc(var(--backdrop-opacity) * ${getBackdropValueForSheet(1 - breakpointOffset, backdropBreakpoint)})`,
1406
- },
1407
- {
1408
- offset: 1,
1409
- opacity: `calc(var(--backdrop-opacity) * ${getBackdropValueForSheet(snapToBreakpoint, backdropBreakpoint)})`,
1410
- },
1411
- ]);
1412
- if (contentAnimation) {
1413
- /**
1414
- * The modal content should scroll at any breakpoint when expandToScroll
1415
- * is disabled. In order to do this, the content needs to be completely
1416
- * viewable so scrolling can access everything. Otherwise, the default
1417
- * behavior would show the content off the screen and only allow
1418
- * scrolling when the sheet is fully expanded.
1419
- */
1420
- contentAnimation.keyframes([
1421
- { offset: 0, maxHeight: `${(1 - breakpointOffset) * 100}%` },
1422
- { offset: 1, maxHeight: `${snapToBreakpoint * 100}%` },
1423
- ]);
1424
- }
1425
- animation.progressStep(0);
1426
- }
1427
- /**
1428
- * Gesture should remain disabled until the
1429
- * snapping animation completes.
1430
- */
1431
- gesture.enable(false);
1432
- if (shouldPreventDismiss) {
1433
- handleCanDismiss(baseEl, animation);
1434
- }
1435
- else if (!shouldRemainOpen) {
1436
- onDismiss();
1437
- }
1438
- /**
1439
- * Enables scrolling immediately if the sheet is about to fully expand
1440
- * or if it allows scrolling at any breakpoint. Without this, there would
1441
- * be a ~500ms delay while the modal animation completes, causing a
1442
- * noticeable lag. Native iOS allows scrolling as soon as the gesture is
1443
- * released, so we align with that behavior.
1444
- */
1445
- if (contentEl && (snapToBreakpoint === breakpoints[breakpoints.length - 1] || !expandToScroll)) {
1446
- contentEl.scrollY = true;
1447
- }
1448
- /**
1449
- * If expandToScroll is disabled and we're animating
1450
- * to close the sheet, we need to swap
1451
- * the footer position to stationary so that it
1452
- * will collapse correctly. We cannot just always swap
1453
- * here or it'll be jittery while animating movement.
1454
- */
1455
- if (!expandToScroll && snapToBreakpoint === 0) {
1456
- swapFooterPosition('stationary');
1457
- }
1458
- return new Promise((resolve) => {
1459
- animation
1460
- .onFinish(() => {
1461
- if (shouldRemainOpen) {
1462
- /**
1463
- * If expandToScroll is disabled, we need to swap
1464
- * the footer position to stationary so that it
1465
- * will act as it would by default.
1466
- */
1467
- if (!expandToScroll) {
1468
- swapFooterPosition('stationary');
1469
- }
1470
- /**
1471
- * Once the snapping animation completes,
1472
- * we need to reset the animation to go
1473
- * from 0 to 1 so users can swipe in any direction.
1474
- * We then set the animation offset to the current
1475
- * breakpoint so that it starts at the snapped position.
1476
- */
1477
- if (wrapperAnimation && backdropAnimation) {
1478
- raf(() => {
1479
- wrapperAnimation.keyframes([...SheetDefaults.WRAPPER_KEYFRAMES]);
1480
- backdropAnimation.keyframes([...SheetDefaults.BACKDROP_KEYFRAMES]);
1481
- contentAnimation === null || contentAnimation === void 0 ? void 0 : contentAnimation.keyframes([...SheetDefaults.CONTENT_KEYFRAMES]);
1482
- animation.progressStart(true, 1 - snapToBreakpoint);
1483
- currentBreakpoint = snapToBreakpoint;
1484
- onBreakpointChange(currentBreakpoint);
1485
- /**
1486
- * Backdrop should become enabled
1487
- * after the backdropBreakpoint value
1488
- */
1489
- const shouldEnableBackdrop = currentBreakpoint > backdropBreakpoint &&
1490
- baseEl.focusTrap !== false &&
1491
- baseEl.showBackdrop !== false;
1492
- if (shouldEnableBackdrop) {
1493
- enableBackdrop();
1494
- }
1495
- else {
1496
- disableBackdrop();
1497
- }
1498
- gesture.enable(true);
1499
- resolve();
1500
- });
1501
- }
1502
- else {
1503
- gesture.enable(true);
1504
- resolve();
1505
- }
1506
- }
1507
- else {
1508
- resolve();
1509
- }
1510
- /**
1511
- * This must be a one time callback
1512
- * otherwise a new callback will
1513
- * be added every time onEnd runs.
1514
- */
1515
- }, { oneTimeCallback: true })
1516
- .progressEnd(1, 0, animated ? 500 : 0);
1517
- });
1518
- };
1519
- /**
1520
- * Calculates the closest breakpoint based on the current velocity and deltaY.
1521
- * This determines where the sheet should snap to when the user releases the
1522
- * gesture.
1523
- *
1524
- * @param velocityY The current velocity of the gesture in the Y direction.
1525
- * @param deltaY The change in Y position since the gesture started.
1526
- * @returns The closest breakpoint value.
1527
- */
1528
- const calculateClosestBreakpoint = (velocityY, deltaY) => {
1529
- const threshold = (deltaY + velocityY * 350) / height;
1530
- const diff = currentBreakpoint - threshold;
1531
- const closest = breakpoints.reduce((a, b) => {
1532
- return Math.abs(b - diff) < Math.abs(a - diff) ? b : a;
1533
- });
1534
- return closest;
1535
- };
1536
- /**
1537
- * Calculates the progress of the swipe gesture.
1538
- *
1539
- * The progress is a value between 0 and 1 that represents how far
1540
- * the swipe has progressed towards closing the modal.
1541
- *
1542
- * A value closer to 1 means the modal is closer to being opened,
1543
- * while a value closer to 0 means the modal is closer to being closed.
1544
- *
1545
- * @param currentY The current Y position of the gesture
1546
- * @returns The progress of the sheet gesture
1547
- */
1548
- const calculateProgress = (currentY) => {
1549
- const minBreakpoint = breakpoints[0];
1550
- const maxBreakpoint = breakpoints[breakpoints.length - 1];
1551
- // Convert breakpoints to pixel Y coordinates
1552
- /**
1553
- * The lowest point the sheet can be dragged to aka the point at which
1554
- * the sheet is fully closed.
1555
- */
1556
- const maxY = convertBreakpointToY(minBreakpoint);
1557
- /**
1558
- * The highest point the sheet can be dragged to aka the point at which
1559
- * the sheet is fully open.
1560
- */
1561
- const minY = convertBreakpointToY(maxBreakpoint);
1562
- // The total distance between the fully open and fully closed positions.
1563
- const totalDistance = maxY - minY;
1564
- // The distance from the current position to the fully closed position.
1565
- const distanceFromBottom = maxY - currentY;
1566
- /**
1567
- * The progress represents how far the sheet is from the bottom relative
1568
- * to the total distance. When the user starts swiping up, the progress
1569
- * should be close to 1, and when the user has swiped all the way down,
1570
- * the progress should be close to 0.
1571
- */
1572
- const progress = distanceFromBottom / totalDistance;
1573
- // Round to the nearest thousandth to avoid returning very small decimal
1574
- const roundedProgress = Math.round(progress * 1000) / 1000;
1575
- return Math.max(0, Math.min(1, roundedProgress));
1576
- };
1577
- /**
1578
- * Converts a breakpoint value (0 to 1) into a pixel Y coordinate
1579
- * on the screen.
1580
- *
1581
- * @param breakpoint The breakpoint value (e.g., 0.5 for half-open)
1582
- * @returns The pixel Y coordinate on the screen
1583
- */
1584
- const convertBreakpointToY = (breakpoint) => {
1585
- const rect = baseEl.getBoundingClientRect();
1586
- const modalHeight = rect.height;
1587
- // The bottom of the screen.
1588
- const viewportBottom = window.innerHeight;
1589
- /**
1590
- * The active height is how much of the modal is actually showing
1591
- * on the screen for this specific breakpoint.
1592
- */
1593
- const activeHeight = modalHeight * breakpoint;
1594
- /**
1595
- * To find the Y coordinate, start at the bottom of the screen
1596
- * and move up by the active height of the modal.
1597
- *
1598
- * A breakpoint of 1.0 means the active height is the full modal height
1599
- * (fully open). A breakpoint of 0.0 means the active height is 0
1600
- * (fully closed).
1601
- *
1602
- * Since screen Y coordinates get smaller as you go up, we subtract the
1603
- * active height from the viewport bottom.
1604
- */
1605
- return viewportBottom - activeHeight;
1606
- };
1607
- const gesture = createGesture({
1608
- el: wrapperEl,
1609
- gestureName: 'modalSheet',
1610
- gesturePriority: 40,
1611
- direction: 'y',
1612
- threshold: 10,
1613
- canStart,
1614
- onStart,
1615
- onMove,
1616
- onEnd,
1617
- });
1618
- return {
1619
- gesture,
1620
- moveSheetToBreakpoint,
1621
- };
1622
- };
1623
-
1624
- const modalIosCss = ":host{--width:100%;--min-width:auto;--max-width:auto;--height:100%;--min-height:auto;--max-height:auto;--overflow:hidden;--border-radius:0;--border-width:0;--border-style:none;--border-color:transparent;--background:var(--ion-background-color, #fff);--box-shadow:none;--backdrop-opacity:0;left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:absolute;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;outline:none;color:var(--ion-text-color, #000);contain:strict}.modal-wrapper,ion-backdrop{pointer-events:auto}:host(.overlay-hidden){display:none}.modal-wrapper,.modal-shadow{border-radius:var(--border-radius);width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow);overflow:var(--overflow);z-index:10}.modal-shadow{position:absolute;background:transparent}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--width:600px;--height:500px;--ion-safe-area-top:0px;--ion-safe-area-bottom:0px;--ion-safe-area-right:0px;--ion-safe-area-left:0px}}@media only screen and (min-width: 768px) and (min-height: 768px){:host{--width:600px;--height:600px}}.modal-handle{left:0px;right:0px;top:5px;border-radius:8px;-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;position:absolute;width:36px;height:5px;-webkit-transform:translateZ(0);transform:translateZ(0);border:0;background:var(--ion-color-step-350, var(--ion-background-color-step-350, #c0c0be));cursor:pointer;z-index:11}.modal-handle::before{-webkit-padding-start:4px;padding-inline-start:4px;-webkit-padding-end:4px;padding-inline-end:4px;padding-top:4px;padding-bottom:4px;position:absolute;width:36px;height:5px;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);content:\"\"}:host(.modal-sheet){--height:calc(100% - (var(--ion-safe-area-top) + 10px))}:host(.modal-sheet) .modal-wrapper,:host(.modal-sheet) .modal-shadow{position:absolute;bottom:0}:host(.modal-sheet.modal-no-expand-scroll) ion-footer{position:absolute;bottom:0;width:var(--width)}:host{--backdrop-opacity:var(--ion-backdrop-opacity, 0.4)}:host(.modal-card),:host(.modal-sheet){--border-radius:10px}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--border-radius:10px}}.modal-wrapper{-webkit-transform:translate3d(0, 100%, 0);transform:translate3d(0, 100%, 0)}@media screen and (max-width: 767px){@supports (width: max(0px, 1px)){:host(.modal-card){--height:calc(100% - max(30px, var(--ion-safe-area-top)) - 10px)}}@supports not (width: max(0px, 1px)){:host(.modal-card){--height:calc(100% - 40px)}}:host(.modal-card) .modal-wrapper{border-start-start-radius:var(--border-radius);border-start-end-radius:var(--border-radius);border-end-end-radius:0;border-end-start-radius:0}:host(.modal-card){--backdrop-opacity:0;--width:100%;-ms-flex-align:end;align-items:flex-end}:host(.modal-card) .modal-shadow{display:none}:host(.modal-card) ion-backdrop{pointer-events:none}}@media screen and (min-width: 768px){:host(.modal-card){--width:calc(100% - 120px);--height:calc(100% - (120px + var(--ion-safe-area-top) + var(--ion-safe-area-bottom)));--max-width:720px;--max-height:1000px;--backdrop-opacity:0;--box-shadow:0px 0px 30px 10px rgba(0, 0, 0, 0.1);-webkit-transition:all 0.5s ease-in-out;transition:all 0.5s ease-in-out}:host(.modal-card) .modal-wrapper{-webkit-box-shadow:none;box-shadow:none}:host(.modal-card) .modal-shadow{-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow)}}:host(.modal-sheet) .modal-wrapper{border-start-start-radius:var(--border-radius);border-start-end-radius:var(--border-radius);border-end-end-radius:0;border-end-start-radius:0}";
1625
-
1626
- const modalMdCss = ":host{--width:100%;--min-width:auto;--max-width:auto;--height:100%;--min-height:auto;--max-height:auto;--overflow:hidden;--border-radius:0;--border-width:0;--border-style:none;--border-color:transparent;--background:var(--ion-background-color, #fff);--box-shadow:none;--backdrop-opacity:0;left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:absolute;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;outline:none;color:var(--ion-text-color, #000);contain:strict}.modal-wrapper,ion-backdrop{pointer-events:auto}:host(.overlay-hidden){display:none}.modal-wrapper,.modal-shadow{border-radius:var(--border-radius);width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow);overflow:var(--overflow);z-index:10}.modal-shadow{position:absolute;background:transparent}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--width:600px;--height:500px;--ion-safe-area-top:0px;--ion-safe-area-bottom:0px;--ion-safe-area-right:0px;--ion-safe-area-left:0px}}@media only screen and (min-width: 768px) and (min-height: 768px){:host{--width:600px;--height:600px}}.modal-handle{left:0px;right:0px;top:5px;border-radius:8px;-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;position:absolute;width:36px;height:5px;-webkit-transform:translateZ(0);transform:translateZ(0);border:0;background:var(--ion-color-step-350, var(--ion-background-color-step-350, #c0c0be));cursor:pointer;z-index:11}.modal-handle::before{-webkit-padding-start:4px;padding-inline-start:4px;-webkit-padding-end:4px;padding-inline-end:4px;padding-top:4px;padding-bottom:4px;position:absolute;width:36px;height:5px;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);content:\"\"}:host(.modal-sheet){--height:calc(100% - (var(--ion-safe-area-top) + 10px))}:host(.modal-sheet) .modal-wrapper,:host(.modal-sheet) .modal-shadow{position:absolute;bottom:0}:host(.modal-sheet.modal-no-expand-scroll) ion-footer{position:absolute;bottom:0;width:var(--width)}:host{--backdrop-opacity:var(--ion-backdrop-opacity, 0.32)}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--border-radius:2px;--box-shadow:0 28px 48px rgba(0, 0, 0, 0.4)}}.modal-wrapper{-webkit-transform:translate3d(0, 40px, 0);transform:translate3d(0, 40px, 0);opacity:0.01}";
1627
-
1628
- const Modal = /*@__PURE__*/ proxyCustomElement(class Modal extends HTMLElement {
1629
- constructor(registerHost) {
1630
- super();
1631
- if (registerHost !== false) {
1632
- this.__registerHost();
1633
- }
1634
- this.__attachShadow();
1635
- this.didPresent = createEvent(this, "ionModalDidPresent", 7);
1636
- this.willPresent = createEvent(this, "ionModalWillPresent", 7);
1637
- this.willDismiss = createEvent(this, "ionModalWillDismiss", 7);
1638
- this.didDismiss = createEvent(this, "ionModalDidDismiss", 7);
1639
- this.ionBreakpointDidChange = createEvent(this, "ionBreakpointDidChange", 7);
1640
- this.didPresentShorthand = createEvent(this, "didPresent", 7);
1641
- this.willPresentShorthand = createEvent(this, "willPresent", 7);
1642
- this.willDismissShorthand = createEvent(this, "willDismiss", 7);
1643
- this.didDismissShorthand = createEvent(this, "didDismiss", 7);
1644
- this.ionMount = createEvent(this, "ionMount", 7);
1645
- this.ionDragStart = createEvent(this, "ionDragStart", 7);
1646
- this.ionDragMove = createEvent(this, "ionDragMove", 7);
1647
- this.ionDragEnd = createEvent(this, "ionDragEnd", 7);
1648
- this.lockController = createLockController();
1649
- this.triggerController = createTriggerController();
1650
- this.coreDelegate = CoreDelegate();
1651
- this.isSheetModal = false;
1652
- this.inheritedAttributes = {};
1653
- this.inline = false;
1654
- // Whether or not modal is being dismissed via gesture
1655
- this.gestureAnimationDismissing = false;
1656
- this.presented = false;
1657
- /** @internal */
1658
- this.hasController = false;
1659
- /**
1660
- * If `true`, the keyboard will be automatically dismissed when the overlay is presented.
1661
- */
1662
- this.keyboardClose = true;
1663
- /**
1664
- * Controls whether scrolling or dragging within the sheet modal expands
1665
- * it to a larger breakpoint. This only takes effect when `breakpoints`
1666
- * and `initialBreakpoint` are set.
1667
- *
1668
- * If `true`, scrolling or dragging anywhere in the modal will first expand
1669
- * it to the next breakpoint. Once fully expanded, scrolling will affect the
1670
- * content.
1671
- * If `false`, scrolling will always affect the content. The modal will
1672
- * only expand when dragging the header or handle. The modal will close when
1673
- * dragging the header or handle. It can also be closed when dragging the
1674
- * content, but only if the content is scrolled to the top.
1675
- */
1676
- this.expandToScroll = true;
1677
- /**
1678
- * A decimal value between 0 and 1 that indicates the
1679
- * point after which the backdrop will begin to fade in
1680
- * when using a sheet modal. Prior to this point, the
1681
- * backdrop will be hidden and the content underneath
1682
- * the sheet can be interacted with. This value is exclusive
1683
- * meaning the backdrop will become active after the value
1684
- * specified.
1685
- */
1686
- this.backdropBreakpoint = 0;
1687
- /**
1688
- * The interaction behavior for the sheet modal when the handle is pressed.
1689
- *
1690
- * Defaults to `"none"`, which means the modal will not change size or position when the handle is pressed.
1691
- * Set to `"cycle"` to let the modal cycle between available breakpoints when pressed.
1692
- *
1693
- * Handle behavior is unavailable when the `handle` property is set to `false` or
1694
- * when the `breakpoints` property is not set (using a fullscreen or card modal).
1695
- */
1696
- this.handleBehavior = 'none';
1697
- /**
1698
- * If `true`, the modal will be dismissed when the backdrop is clicked.
1699
- */
1700
- this.backdropDismiss = true;
1701
- /**
1702
- * If `true`, a backdrop will be displayed behind the modal.
1703
- * This property controls whether or not the backdrop
1704
- * darkens the screen when the modal is presented.
1705
- * It does not control whether or not the backdrop
1706
- * is active or present in the DOM.
1707
- */
1708
- this.showBackdrop = true;
1709
- /**
1710
- * If `true`, the modal will animate.
1711
- */
1712
- this.animated = true;
1713
- /**
1714
- * If `true`, the modal will open. If `false`, the modal will close.
1715
- * Use this if you need finer grained control over presentation, otherwise
1716
- * just use the modalController or the `trigger` property.
1717
- * Note: `isOpen` will not automatically be set back to `false` when
1718
- * the modal dismisses. You will need to do that in your code.
1719
- */
1720
- this.isOpen = false;
1721
- /**
1722
- * If `true`, the component passed into `ion-modal` will
1723
- * automatically be mounted when the modal is created. The
1724
- * component will remain mounted even when the modal is dismissed.
1725
- * However, the component will be destroyed when the modal is
1726
- * destroyed. This property is not reactive and should only be
1727
- * used when initially creating a modal.
1728
- *
1729
- * Note: This feature only applies to inline modals in JavaScript
1730
- * frameworks such as Angular, React, and Vue.
1731
- */
1732
- this.keepContentsMounted = false;
1733
- /**
1734
- * If `true`, focus will not be allowed to move outside of this overlay.
1735
- * If `false`, focus will be allowed to move outside of the overlay.
1736
- *
1737
- * In most scenarios this property should remain set to `true`. Setting
1738
- * this property to `false` can cause severe accessibility issues as users
1739
- * relying on assistive technologies may be able to move focus into
1740
- * a confusing state. We recommend only setting this to `false` when
1741
- * absolutely necessary.
1742
- *
1743
- * Developers may want to consider disabling focus trapping if this
1744
- * overlay presents a non-Ionic overlay from a 3rd party library.
1745
- * Developers would disable focus trapping on the Ionic overlay
1746
- * when presenting the 3rd party overlay and then re-enable
1747
- * focus trapping when dismissing the 3rd party overlay and moving
1748
- * focus back to the Ionic overlay.
1749
- */
1750
- this.focusTrap = true;
1751
- /**
1752
- * Determines whether or not a modal can dismiss
1753
- * when calling the `dismiss` method.
1754
- *
1755
- * If the value is `true` or the value's function returns `true`, the modal will close when trying to dismiss.
1756
- * If the value is `false` or the value's function returns `false`, the modal will not close when trying to dismiss.
1757
- *
1758
- * See https://ionicframework.com/docs/troubleshooting/runtime#accessing-this
1759
- * if you need to access `this` from within the callback.
1760
- */
1761
- this.canDismiss = true;
1762
- this.onHandleClick = () => {
1763
- const { sheetTransition, handleBehavior } = this;
1764
- if (handleBehavior !== 'cycle' || sheetTransition !== undefined) {
1765
- /**
1766
- * The sheet modal should not advance to the next breakpoint
1767
- * if the handle behavior is not `cycle` or if the handle
1768
- * is clicked while the sheet is moving to a breakpoint.
1769
- */
1770
- return;
1771
- }
1772
- this.moveToNextBreakpoint();
1773
- };
1774
- this.onBackdropTap = () => {
1775
- const { sheetTransition } = this;
1776
- if (sheetTransition !== undefined) {
1777
- /**
1778
- * When the handle is double clicked at the largest breakpoint,
1779
- * it will start to move to the first breakpoint. While transitioning,
1780
- * the backdrop will often receive the second click. We prevent the
1781
- * backdrop from dismissing the modal while moving between breakpoints.
1782
- */
1783
- return;
1784
- }
1785
- this.dismiss(undefined, BACKDROP);
1786
- };
1787
- this.onLifecycle = (modalEvent) => {
1788
- const el = this.usersElement;
1789
- const name = LIFECYCLE_MAP[modalEvent.type];
1790
- if (el && name) {
1791
- const ev = new CustomEvent(name, {
1792
- bubbles: false,
1793
- cancelable: false,
1794
- detail: modalEvent.detail,
1795
- });
1796
- el.dispatchEvent(ev);
1797
- }
1798
- };
1799
- /**
1800
- * When the modal receives focus directly, pass focus to the handle
1801
- * if it exists and is focusable, otherwise let the focus trap handle it.
1802
- */
1803
- this.onModalFocus = (ev) => {
1804
- const { dragHandleEl, el } = this;
1805
- // Only handle focus if the modal itself was focused (not a child element)
1806
- if (ev.target === el && dragHandleEl && dragHandleEl.tabIndex !== -1) {
1807
- dragHandleEl.focus();
1808
- }
1809
- };
1810
- /**
1811
- * When the slot changes, we need to find all the modals in the slot
1812
- * and set the data-parent-ion-modal attribute on them so we can find them
1813
- * and dismiss them when we get dismissed.
1814
- * We need to do it this way because when a modal is opened, it's moved to
1815
- * the end of the body and is no longer an actual child of the modal.
1816
- */
1817
- this.onSlotChange = ({ target }) => {
1818
- const slot = target;
1819
- slot.assignedElements().forEach((el) => {
1820
- el.querySelectorAll('ion-modal').forEach((childModal) => {
1821
- // We don't need to write to the DOM if the modal is already tagged
1822
- // If this is a deeply nested modal, this effect should cascade so we don't
1823
- // need to worry about another modal claiming the same child.
1824
- if (childModal.getAttribute('data-parent-ion-modal') === null) {
1825
- childModal.setAttribute('data-parent-ion-modal', this.el.id);
1826
- }
1827
- });
1828
- });
1829
- };
1830
- }
1831
- onIsOpenChange(newValue, oldValue) {
1832
- if (newValue === true && oldValue === false) {
1833
- this.present();
1834
- }
1835
- else if (newValue === false && oldValue === true) {
1836
- this.dismiss();
1837
- }
1838
- }
1839
- triggerChanged() {
1840
- const { trigger, el, triggerController } = this;
1841
- if (trigger) {
1842
- triggerController.addClickListener(el, trigger);
1843
- }
1844
- }
1845
- onWindowResize() {
1846
- // Only handle resize for iOS card modals when no custom animations are provided
1847
- if (getIonMode(this) !== 'ios' || !this.presentingElement || this.enterAnimation || this.leaveAnimation) {
1848
- return;
1849
- }
1850
- clearTimeout(this.resizeTimeout);
1851
- this.resizeTimeout = setTimeout(() => {
1852
- this.handleViewTransition();
1853
- }, 50); // Debounce to avoid excessive calls during active resizing
1854
- }
1855
- breakpointsChanged(breakpoints) {
1856
- if (breakpoints !== undefined) {
1857
- this.sortedBreakpoints = breakpoints.sort((a, b) => a - b);
1858
- }
1859
- }
1860
- connectedCallback() {
1861
- const { el } = this;
1862
- prepareOverlay(el);
1863
- this.triggerChanged();
1864
- }
1865
- disconnectedCallback() {
1866
- this.triggerController.removeClickListener();
1867
- this.cleanupViewTransitionListener();
1868
- this.cleanupParentRemovalObserver();
1869
- }
1870
- componentWillLoad() {
1871
- var _a;
1872
- const { breakpoints, initialBreakpoint, el, htmlAttributes } = this;
1873
- const isSheetModal = (this.isSheetModal = breakpoints !== undefined && initialBreakpoint !== undefined);
1874
- const attributesToInherit = ['aria-label', 'role'];
1875
- this.inheritedAttributes = inheritAttributes(el, attributesToInherit);
1876
- // Cache original parent before modal gets moved to body during presentation
1877
- if (el.parentNode) {
1878
- this.cachedOriginalParent = el.parentNode;
1879
- }
1880
- /**
1881
- * When using a controller modal you can set attributes
1882
- * using the htmlAttributes property. Since the above attributes
1883
- * need to be inherited inside of the modal, we need to look
1884
- * and see if these attributes are being set via htmlAttributes.
1885
- *
1886
- * We could alternatively move this to componentDidLoad to simplify the work
1887
- * here, but we'd then need to make inheritedAttributes a State variable,
1888
- * thus causing another render to always happen after the first render.
1889
- */
1890
- if (htmlAttributes !== undefined) {
1891
- attributesToInherit.forEach((attribute) => {
1892
- const attributeValue = htmlAttributes[attribute];
1893
- if (attributeValue) {
1894
- /**
1895
- * If an attribute we need to inherit was
1896
- * set using htmlAttributes then add it to
1897
- * inheritedAttributes and remove it from htmlAttributes.
1898
- * This ensures the attribute is inherited and not
1899
- * set on the host.
1900
- *
1901
- * In this case, if an inherited attribute is set
1902
- * on the host element and using htmlAttributes then
1903
- * htmlAttributes wins, but that's not a pattern that we recommend.
1904
- * The only time you'd need htmlAttributes is when using modalController.
1905
- */
1906
- this.inheritedAttributes = Object.assign(Object.assign({}, this.inheritedAttributes), { [attribute]: htmlAttributes[attribute] });
1907
- delete htmlAttributes[attribute];
1908
- }
1909
- });
1910
- }
1911
- if (isSheetModal) {
1912
- this.currentBreakpoint = this.initialBreakpoint;
1913
- }
1914
- if (breakpoints !== undefined && initialBreakpoint !== undefined && !breakpoints.includes(initialBreakpoint)) {
1915
- printIonWarning('[ion-modal] - Your breakpoints array must include the initialBreakpoint value.');
1916
- }
1917
- if (!((_a = this.htmlAttributes) === null || _a === void 0 ? void 0 : _a.id)) {
1918
- setOverlayId(this.el);
1919
- }
1920
- }
1921
- componentDidLoad() {
1922
- /**
1923
- * If modal was rendered with isOpen="true"
1924
- * then we should open modal immediately.
1925
- */
1926
- if (this.isOpen === true) {
1927
- raf(() => this.present());
1928
- }
1929
- this.breakpointsChanged(this.breakpoints);
1930
- /**
1931
- * When binding values in frameworks such as Angular
1932
- * it is possible for the value to be set after the Web Component
1933
- * initializes but before the value watcher is set up in Stencil.
1934
- * As a result, the watcher callback may not be fired.
1935
- * We work around this by manually calling the watcher
1936
- * callback when the component has loaded and the watcher
1937
- * is configured.
1938
- */
1939
- this.triggerChanged();
1940
- }
1941
- /**
1942
- * Determines whether or not an overlay
1943
- * is being used inline or via a controller/JS
1944
- * and returns the correct delegate.
1945
- * By default, subsequent calls to getDelegate
1946
- * will use a cached version of the delegate.
1947
- * This is useful for calling dismiss after
1948
- * present so that the correct delegate is given.
1949
- */
1950
- getDelegate(force = false) {
1951
- if (this.workingDelegate && !force) {
1952
- return {
1953
- delegate: this.workingDelegate,
1954
- inline: this.inline,
1955
- };
1956
- }
1957
- /**
1958
- * If using overlay inline
1959
- * we potentially need to use the coreDelegate
1960
- * so that this works in vanilla JS apps.
1961
- * If a developer has presented this component
1962
- * via a controller, then we can assume
1963
- * the component is already in the
1964
- * correct place.
1965
- */
1966
- const parentEl = this.el.parentNode;
1967
- const inline = (this.inline = parentEl !== null && !this.hasController);
1968
- const delegate = (this.workingDelegate = inline ? this.delegate || this.coreDelegate : this.delegate);
1969
- return { inline, delegate };
1970
- }
1971
- /**
1972
- * Determines whether or not the
1973
- * modal is allowed to dismiss based
1974
- * on the state of the canDismiss prop.
1975
- */
1976
- async checkCanDismiss(data, role) {
1977
- const { canDismiss } = this;
1978
- if (typeof canDismiss === 'function') {
1979
- return canDismiss(data, role);
1980
- }
1981
- return canDismiss;
1982
- }
1983
- /**
1984
- * Present the modal overlay after it has been created.
1985
- */
1986
- async present() {
1987
- const unlock = await this.lockController.lock();
1988
- if (this.presented) {
1989
- unlock();
1990
- return;
1991
- }
1992
- const { presentingElement, el } = this;
1993
- /**
1994
- * If the modal is presented multiple times (inline modals), we
1995
- * need to reset the current breakpoint to the initial breakpoint.
1996
- */
1997
- this.currentBreakpoint = this.initialBreakpoint;
1998
- const { inline, delegate } = this.getDelegate(true);
1999
- /**
2000
- * Emit ionMount so JS Frameworks have an opportunity
2001
- * to add the child component to the DOM. The child
2002
- * component will be assigned to this.usersElement below.
2003
- */
2004
- this.ionMount.emit();
2005
- this.usersElement = await attachComponent(delegate, el, this.component, ['ion-page'], this.componentProps, inline);
2006
- /**
2007
- * When using the lazy loaded build of Stencil, we need to wait
2008
- * for every Stencil component instance to be ready before presenting
2009
- * otherwise there can be a flash of unstyled content. With the
2010
- * custom elements bundle we need to wait for the JS framework
2011
- * mount the inner contents of the overlay otherwise WebKit may
2012
- * get the transition incorrect.
2013
- */
2014
- if (hasLazyBuild(el)) {
2015
- await deepReady(this.usersElement);
2016
- /**
2017
- * If keepContentsMounted="true" then the
2018
- * JS Framework has already mounted the inner
2019
- * contents so there is no need to wait.
2020
- * Otherwise, we need to wait for the JS
2021
- * Framework to mount the inner contents
2022
- * of this component.
2023
- */
2024
- }
2025
- else if (!this.keepContentsMounted) {
2026
- await waitForMount();
2027
- }
2028
- writeTask(() => this.el.classList.add('show-modal'));
2029
- const hasCardModal = presentingElement !== undefined;
2030
- /**
2031
- * We need to change the status bar at the
2032
- * start of the animation so that it completes
2033
- * by the time the card animation is done.
2034
- */
2035
- if (hasCardModal && getIonMode(this) === 'ios') {
2036
- // Cache the original status bar color before the modal is presented
2037
- this.statusBarStyle = await StatusBar.getStyle();
2038
- setCardStatusBarDark();
2039
- }
2040
- await present(this, 'modalEnter', iosEnterAnimation, mdEnterAnimation, {
2041
- presentingEl: presentingElement,
2042
- currentBreakpoint: this.initialBreakpoint,
2043
- backdropBreakpoint: this.backdropBreakpoint,
2044
- expandToScroll: this.expandToScroll,
2045
- });
2046
- /* tslint:disable-next-line */
2047
- if (typeof window !== 'undefined') {
2048
- /**
2049
- * This needs to be setup before any
2050
- * non-transition async work so it can be dereferenced
2051
- * in the dismiss method. The dismiss method
2052
- * only waits for the entering transition
2053
- * to finish. It does not wait for all of the `present`
2054
- * method to resolve.
2055
- */
2056
- this.keyboardOpenCallback = () => {
2057
- if (this.gesture) {
2058
- /**
2059
- * When the native keyboard is opened and the webview
2060
- * is resized, the gesture implementation will become unresponsive
2061
- * and enter a free-scroll mode.
2062
- *
2063
- * When the keyboard is opened, we disable the gesture for
2064
- * a single frame and re-enable once the contents have repositioned
2065
- * from the keyboard placement.
2066
- */
2067
- this.gesture.enable(false);
2068
- raf(() => {
2069
- if (this.gesture) {
2070
- this.gesture.enable(true);
2071
- }
2072
- });
2073
- }
2074
- };
2075
- window.addEventListener(KEYBOARD_DID_OPEN, this.keyboardOpenCallback);
2076
- }
2077
- /**
2078
- * Recalculate isSheetModal because framework bindings (e.g., Angular)
2079
- * may not have been applied when componentWillLoad ran.
2080
- */
2081
- const isSheetModal = this.breakpoints !== undefined && this.initialBreakpoint !== undefined;
2082
- this.isSheetModal = isSheetModal;
2083
- if (isSheetModal) {
2084
- this.initSheetGesture();
2085
- }
2086
- else if (hasCardModal) {
2087
- this.initSwipeToClose();
2088
- }
2089
- // Initialize view transition listener for iOS card modals
2090
- this.initViewTransitionListener();
2091
- // Initialize parent removal observer
2092
- this.initParentRemovalObserver();
2093
- unlock();
2094
- }
2095
- initSwipeToClose() {
2096
- var _a;
2097
- if (getIonMode(this) !== 'ios') {
2098
- return;
2099
- }
2100
- const { el } = this;
2101
- // All of the elements needed for the swipe gesture
2102
- // should be in the DOM and referenced by now, except
2103
- // for the presenting el
2104
- const animationBuilder = this.leaveAnimation || config.get('modalLeave', iosLeaveAnimation);
2105
- const ani = (this.animation = animationBuilder(el, {
2106
- presentingEl: this.presentingElement,
2107
- expandToScroll: this.expandToScroll,
2108
- }));
2109
- const contentEl = findIonContent(el);
2110
- if (!contentEl) {
2111
- printIonContentErrorMsg(el);
2112
- return;
2113
- }
2114
- const statusBarStyle = (_a = this.statusBarStyle) !== null && _a !== void 0 ? _a : Style.Default;
2115
- this.gesture = createSwipeToCloseGesture(el, ani, statusBarStyle, () => this.cardOnDismiss(), () => this.onDragStart(), (detail) => this.onDragMove(detail), (detail) => this.onDragEnd(detail));
2116
- this.gesture.enable(true);
2117
- }
2118
- initSheetGesture() {
2119
- const { wrapperEl, initialBreakpoint, backdropBreakpoint } = this;
2120
- if (!wrapperEl || initialBreakpoint === undefined) {
2121
- return;
2122
- }
2123
- const animationBuilder = this.enterAnimation || config.get('modalEnter', iosEnterAnimation);
2124
- const ani = (this.animation = animationBuilder(this.el, {
2125
- presentingEl: this.presentingElement,
2126
- currentBreakpoint: initialBreakpoint,
2127
- backdropBreakpoint,
2128
- expandToScroll: this.expandToScroll,
2129
- }));
2130
- ani.progressStart(true, 1);
2131
- const { gesture, moveSheetToBreakpoint } = createSheetGesture(this.el, this.backdropEl, wrapperEl, initialBreakpoint, backdropBreakpoint, ani, this.sortedBreakpoints, this.expandToScroll, () => { var _a; return (_a = this.currentBreakpoint) !== null && _a !== void 0 ? _a : 0; }, () => this.sheetOnDismiss(), (breakpoint) => {
2132
- if (this.currentBreakpoint !== breakpoint) {
2133
- this.currentBreakpoint = breakpoint;
2134
- this.ionBreakpointDidChange.emit({ breakpoint });
2135
- }
2136
- }, () => this.onDragStart(), (detail) => this.onDragMove(detail), (detail) => this.onDragEnd(detail));
2137
- this.gesture = gesture;
2138
- this.moveSheetToBreakpoint = moveSheetToBreakpoint;
2139
- this.gesture.enable(true);
2140
- /**
2141
- * When backdrop interaction is allowed, nested router outlets from child routes
2142
- * may block pointer events to parent content. Apply passthrough styles only when
2143
- * the modal was the sole content of a child route page.
2144
- * See https://github.com/ionic-team/ionic-framework/issues/30700
2145
- */
2146
- const backdropNotBlocking = this.showBackdrop === false || this.focusTrap === false || backdropBreakpoint > 0;
2147
- if (backdropNotBlocking) {
2148
- this.setupChildRoutePassthrough();
2149
- }
2150
- }
2151
- /**
2152
- * For sheet modals that allow background interaction, sets up pointer-events
2153
- * passthrough on child route page wrappers and nested router outlets.
2154
- */
2155
- setupChildRoutePassthrough() {
2156
- var _a;
2157
- // Cache the page parent for cleanup
2158
- this.cachedPageParent = this.getOriginalPageParent();
2159
- const pageParent = this.cachedPageParent;
2160
- // Skip ion-app (controller modals) and pages with visible sibling content next to the modal
2161
- if (!pageParent || pageParent.tagName === 'ION-APP') {
2162
- return;
2163
- }
2164
- const hasVisibleContent = Array.from(pageParent.children).some((child) => {
2165
- var _a;
2166
- return child !== this.el &&
2167
- !(child instanceof HTMLElement && window.getComputedStyle(child).display === 'none') &&
2168
- child.tagName !== 'TEMPLATE' &&
2169
- child.tagName !== 'SLOT' &&
2170
- !(child.nodeType === Node.TEXT_NODE && !((_a = child.textContent) === null || _a === void 0 ? void 0 : _a.trim()));
2171
- });
2172
- if (hasVisibleContent) {
2173
- return;
2174
- }
2175
- // Child route case: page only contained the modal
2176
- pageParent.classList.add('ion-page-overlay-passthrough');
2177
- // Also make nested router outlets passthrough
2178
- const routerOutlet = pageParent.parentElement;
2179
- if ((routerOutlet === null || routerOutlet === void 0 ? void 0 : routerOutlet.tagName) === 'ION-ROUTER-OUTLET' && ((_a = routerOutlet.parentElement) === null || _a === void 0 ? void 0 : _a.tagName) !== 'ION-APP') {
2180
- routerOutlet.style.setProperty('pointer-events', 'none');
2181
- routerOutlet.setAttribute('data-overlay-passthrough', 'true');
2182
- }
2183
- }
2184
- /**
2185
- * Finds the ion-page ancestor of the modal's original parent location.
2186
- */
2187
- getOriginalPageParent() {
2188
- if (!this.cachedOriginalParent) {
2189
- return null;
2190
- }
2191
- let pageParent = this.cachedOriginalParent;
2192
- while (pageParent && !pageParent.classList.contains('ion-page')) {
2193
- pageParent = pageParent.parentElement;
2194
- }
2195
- return pageParent;
2196
- }
2197
- /**
2198
- * Removes passthrough styles added by setupChildRoutePassthrough.
2199
- */
2200
- cleanupChildRoutePassthrough() {
2201
- const pageParent = this.cachedPageParent;
2202
- if (!pageParent) {
2203
- return;
2204
- }
2205
- pageParent.classList.remove('ion-page-overlay-passthrough');
2206
- const routerOutlet = pageParent.parentElement;
2207
- if (routerOutlet === null || routerOutlet === void 0 ? void 0 : routerOutlet.hasAttribute('data-overlay-passthrough')) {
2208
- routerOutlet.style.removeProperty('pointer-events');
2209
- routerOutlet.removeAttribute('data-overlay-passthrough');
2210
- }
2211
- // Clear the cached reference
2212
- this.cachedPageParent = undefined;
2213
- }
2214
- sheetOnDismiss() {
2215
- /**
2216
- * While the gesture animation is finishing
2217
- * it is possible for a user to tap the backdrop.
2218
- * This would result in the dismiss animation
2219
- * being played again. Typically this is avoided
2220
- * by setting `presented = false` on the overlay
2221
- * component; however, we cannot do that here as
2222
- * that would prevent the element from being
2223
- * removed from the DOM.
2224
- */
2225
- this.gestureAnimationDismissing = true;
2226
- this.animation.onFinish(async () => {
2227
- this.currentBreakpoint = 0;
2228
- this.ionBreakpointDidChange.emit({ breakpoint: this.currentBreakpoint });
2229
- await this.dismiss(undefined, GESTURE);
2230
- this.gestureAnimationDismissing = false;
2231
- });
2232
- }
2233
- cardOnDismiss() {
2234
- /**
2235
- * While the gesture animation is finishing
2236
- * it is possible for a user to tap the backdrop.
2237
- * This would result in the dismiss animation
2238
- * being played again. Typically this is avoided
2239
- * by setting `presented = false` on the overlay
2240
- * component; however, we cannot do that here as
2241
- * that would prevent the element from being
2242
- * removed from the DOM.
2243
- */
2244
- this.gestureAnimationDismissing = true;
2245
- /**
2246
- * Reset the status bar style as the dismiss animation
2247
- * starts otherwise the status bar will be the wrong
2248
- * color for the duration of the dismiss animation.
2249
- * The dismiss method does this as well, but
2250
- * in this case it's only called once the animation
2251
- * has finished.
2252
- */
2253
- setCardStatusBarDefault(this.statusBarStyle);
2254
- this.animation.onFinish(async () => {
2255
- await this.dismiss(undefined, GESTURE);
2256
- this.gestureAnimationDismissing = false;
2257
- });
2258
- }
2259
- /**
2260
- * Dismiss the modal overlay after it has been presented.
2261
- * This is a no-op if the overlay has not been presented yet. If you want
2262
- * to remove an overlay from the DOM that was never presented, use the
2263
- * [remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method.
2264
- *
2265
- * @param data Any data to emit in the dismiss events.
2266
- * @param role The role of the element that is dismissing the modal.
2267
- * For example, `cancel` or `backdrop`.
2268
- */
2269
- async dismiss(data, role) {
2270
- var _a;
2271
- if (this.gestureAnimationDismissing && role !== GESTURE) {
2272
- return false;
2273
- }
2274
- /**
2275
- * Because the canDismiss check below is async,
2276
- * we need to claim a lock before the check happens,
2277
- * in case the dismiss transition does run.
2278
- */
2279
- const unlock = await this.lockController.lock();
2280
- /**
2281
- * Dismiss all child modals. This is especially important in
2282
- * Angular and React because it's possible to lose control of a child
2283
- * modal when the parent modal is dismissed.
2284
- */
2285
- await this.dismissNestedModals();
2286
- /**
2287
- * If a canDismiss handler is responsible
2288
- * for calling the dismiss method, we should
2289
- * not run the canDismiss check again.
2290
- */
2291
- if (role !== 'handler' && !(await this.checkCanDismiss(data, role))) {
2292
- unlock();
2293
- return false;
2294
- }
2295
- const { presentingElement } = this;
2296
- /**
2297
- * We need to start the status bar change
2298
- * before the animation so that the change
2299
- * finishes when the dismiss animation does.
2300
- */
2301
- const hasCardModal = presentingElement !== undefined;
2302
- if (hasCardModal && getIonMode(this) === 'ios') {
2303
- setCardStatusBarDefault(this.statusBarStyle);
2304
- }
2305
- /* tslint:disable-next-line */
2306
- if (typeof window !== 'undefined' && this.keyboardOpenCallback) {
2307
- window.removeEventListener(KEYBOARD_DID_OPEN, this.keyboardOpenCallback);
2308
- this.keyboardOpenCallback = undefined;
2309
- }
2310
- const dismissed = await dismiss(this, data, role, 'modalLeave', iosLeaveAnimation, mdLeaveAnimation, {
2311
- presentingEl: presentingElement,
2312
- currentBreakpoint: (_a = this.currentBreakpoint) !== null && _a !== void 0 ? _a : this.initialBreakpoint,
2313
- backdropBreakpoint: this.backdropBreakpoint,
2314
- expandToScroll: this.expandToScroll,
2315
- });
2316
- if (dismissed) {
2317
- const { delegate } = this.getDelegate();
2318
- await detachComponent(delegate, this.usersElement);
2319
- writeTask(() => this.el.classList.remove('show-modal'));
2320
- if (this.animation) {
2321
- this.animation.destroy();
2322
- }
2323
- if (this.gesture) {
2324
- this.gesture.destroy();
2325
- }
2326
- this.cleanupViewTransitionListener();
2327
- this.cleanupParentRemovalObserver();
2328
- this.cleanupChildRoutePassthrough();
2329
- }
2330
- this.currentBreakpoint = undefined;
2331
- this.animation = undefined;
2332
- unlock();
2333
- return dismissed;
2334
- }
2335
- /**
2336
- * Returns a promise that resolves when the modal did dismiss.
2337
- */
2338
- onDidDismiss() {
2339
- return eventMethod(this.el, 'ionModalDidDismiss');
2340
- }
2341
- /**
2342
- * Returns a promise that resolves when the modal will dismiss.
2343
- */
2344
- onWillDismiss() {
2345
- return eventMethod(this.el, 'ionModalWillDismiss');
2346
- }
2347
- /**
2348
- * Move a sheet style modal to a specific breakpoint.
2349
- *
2350
- * @param breakpoint The breakpoint value to move the sheet modal to.
2351
- * Must be a value defined in your `breakpoints` array.
2352
- */
2353
- async setCurrentBreakpoint(breakpoint) {
2354
- if (!this.isSheetModal) {
2355
- printIonWarning('[ion-modal] - setCurrentBreakpoint is only supported on sheet modals.');
2356
- return;
2357
- }
2358
- if (!this.breakpoints.includes(breakpoint)) {
2359
- printIonWarning(`[ion-modal] - Attempted to set invalid breakpoint value ${breakpoint}. Please double check that the breakpoint value is part of your defined breakpoints.`);
2360
- return;
2361
- }
2362
- const { currentBreakpoint, moveSheetToBreakpoint, canDismiss, breakpoints, animated } = this;
2363
- if (currentBreakpoint === breakpoint) {
2364
- return;
2365
- }
2366
- if (moveSheetToBreakpoint) {
2367
- this.sheetTransition = moveSheetToBreakpoint({
2368
- breakpoint,
2369
- breakpointOffset: 1 - currentBreakpoint,
2370
- canDismiss: canDismiss !== undefined && canDismiss !== true && breakpoints[0] === 0,
2371
- animated,
2372
- });
2373
- await this.sheetTransition;
2374
- this.sheetTransition = undefined;
2375
- }
2376
- }
2377
- /**
2378
- * Returns the current breakpoint of a sheet style modal
2379
- */
2380
- async getCurrentBreakpoint() {
2381
- return this.currentBreakpoint;
2382
- }
2383
- async moveToNextBreakpoint() {
2384
- const { breakpoints, currentBreakpoint } = this;
2385
- if (!breakpoints || currentBreakpoint == null) {
2386
- /**
2387
- * If the modal does not have breakpoints and/or the current
2388
- * breakpoint is not set, we can't move to the next breakpoint.
2389
- */
2390
- return false;
2391
- }
2392
- const allowedBreakpoints = breakpoints.filter((b) => b !== 0);
2393
- const currentBreakpointIndex = allowedBreakpoints.indexOf(currentBreakpoint);
2394
- const nextBreakpointIndex = (currentBreakpointIndex + 1) % allowedBreakpoints.length;
2395
- const nextBreakpoint = allowedBreakpoints[nextBreakpointIndex];
2396
- /**
2397
- * Sets the current breakpoint to the next available breakpoint.
2398
- * If the current breakpoint is the last breakpoint, we set the current
2399
- * breakpoint to the first non-zero breakpoint to avoid dismissing the sheet.
2400
- */
2401
- await this.setCurrentBreakpoint(nextBreakpoint);
2402
- return true;
2403
- }
2404
- initViewTransitionListener() {
2405
- // Only enable for iOS card modals when no custom animations are provided
2406
- if (getIonMode(this) !== 'ios' || !this.presentingElement || this.enterAnimation || this.leaveAnimation) {
2407
- return;
2408
- }
2409
- // Set initial view state
2410
- this.currentViewIsPortrait = window.innerWidth < 768;
2411
- }
2412
- handleViewTransition() {
2413
- // Only run view transitions when the modal is presented
2414
- if (!this.presented) {
2415
- return;
2416
- }
2417
- const isPortrait = window.innerWidth < 768;
2418
- // Only transition if view state actually changed
2419
- if (this.currentViewIsPortrait === isPortrait) {
2420
- return;
2421
- }
2422
- // Cancel any ongoing transition animation
2423
- if (this.viewTransitionAnimation) {
2424
- this.viewTransitionAnimation.destroy();
2425
- this.viewTransitionAnimation = undefined;
2426
- }
2427
- const { presentingElement } = this;
2428
- if (!presentingElement) {
2429
- return;
2430
- }
2431
- // Create transition animation
2432
- let transitionAnimation;
2433
- if (this.currentViewIsPortrait && !isPortrait) {
2434
- // Portrait to landscape transition
2435
- transitionAnimation = portraitToLandscapeTransition(this.el, {
2436
- presentingEl: presentingElement});
2437
- }
2438
- else {
2439
- // Landscape to portrait transition
2440
- transitionAnimation = landscapeToPortraitTransition(this.el, {
2441
- presentingEl: presentingElement});
2442
- }
2443
- // Update state and play animation
2444
- this.currentViewIsPortrait = isPortrait;
2445
- this.viewTransitionAnimation = transitionAnimation;
2446
- transitionAnimation.play().then(() => {
2447
- this.viewTransitionAnimation = undefined;
2448
- // After orientation transition, recreate the swipe-to-close gesture
2449
- // with updated animation that reflects the new presenting element state
2450
- this.reinitSwipeToClose();
2451
- });
2452
- }
2453
- cleanupViewTransitionListener() {
2454
- // Clear any pending resize timeout
2455
- if (this.resizeTimeout) {
2456
- clearTimeout(this.resizeTimeout);
2457
- this.resizeTimeout = undefined;
2458
- }
2459
- if (this.viewTransitionAnimation) {
2460
- this.viewTransitionAnimation.destroy();
2461
- this.viewTransitionAnimation = undefined;
2462
- }
2463
- }
2464
- reinitSwipeToClose() {
2465
- // Only reinitialize if we have a presenting element and are on iOS
2466
- if (getIonMode(this) !== 'ios' || !this.presentingElement) {
2467
- return;
2468
- }
2469
- // Clean up existing gesture and animation
2470
- if (this.gesture) {
2471
- this.gesture.destroy();
2472
- this.gesture = undefined;
2473
- }
2474
- if (this.animation) {
2475
- // Properly end the progress-based animation at initial state before destroying
2476
- // to avoid leaving modal in intermediate swipe position
2477
- this.animation.progressEnd(0, 0, 0);
2478
- this.animation.destroy();
2479
- this.animation = undefined;
2480
- }
2481
- // Force the modal back to the correct position or it could end up
2482
- // in a weird state after destroying the animation
2483
- raf(() => {
2484
- this.ensureCorrectModalPosition();
2485
- this.initSwipeToClose();
2486
- });
2487
- }
2488
- ensureCorrectModalPosition() {
2489
- const { el, presentingElement } = this;
2490
- const root = getElementRoot(el);
2491
- const wrapperEl = root.querySelector('.modal-wrapper');
2492
- if (wrapperEl) {
2493
- wrapperEl.style.transform = 'translateY(0vh)';
2494
- wrapperEl.style.opacity = '1';
2495
- }
2496
- if ((presentingElement === null || presentingElement === void 0 ? void 0 : presentingElement.tagName) === 'ION-MODAL') {
2497
- const isPortrait = window.innerWidth < 768;
2498
- if (isPortrait) {
2499
- const transformOffset = !CSS.supports('width', 'max(0px, 1px)')
2500
- ? '30px'
2501
- : 'max(30px, var(--ion-safe-area-top))';
2502
- const scale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
2503
- presentingElement.style.transform = `translateY(${transformOffset}) scale(${scale})`;
2504
- }
2505
- else {
2506
- presentingElement.style.transform = 'translateY(0px) scale(1)';
2507
- }
2508
- }
2509
- }
2510
- async dismissNestedModals() {
2511
- const nestedModals = document.querySelectorAll(`ion-modal[data-parent-ion-modal="${this.el.id}"]`);
2512
- nestedModals === null || nestedModals === void 0 ? void 0 : nestedModals.forEach(async (modal) => {
2513
- await modal.dismiss(undefined, 'parent-dismissed');
2514
- });
2515
- }
2516
- initParentRemovalObserver() {
2517
- if (typeof MutationObserver === 'undefined') {
2518
- return;
2519
- }
2520
- // Only observe if we have a cached parent and are in browser environment
2521
- if (typeof window === 'undefined' || !this.cachedOriginalParent) {
2522
- return;
2523
- }
2524
- // Don't observe document or fragment nodes as they can't be "removed"
2525
- if (this.cachedOriginalParent.nodeType === Node.DOCUMENT_NODE ||
2526
- this.cachedOriginalParent.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
2527
- return;
2528
- }
2529
- /**
2530
- * Don't observe for controller-based modals or when the parent is the
2531
- * app root (document.body or ion-app). These parents won't be removed,
2532
- * and observing document.body with subtree: true causes performance
2533
- * issues with frameworks like Angular during change detection.
2534
- */
2535
- if (this.hasController ||
2536
- this.cachedOriginalParent === document.body ||
2537
- this.cachedOriginalParent.tagName === 'ION-APP') {
2538
- return;
2539
- }
2540
- this.parentRemovalObserver = new MutationObserver((mutations) => {
2541
- mutations.forEach((mutation) => {
2542
- if (mutation.type === 'childList' && mutation.removedNodes.length > 0) {
2543
- // Check if our cached original parent was removed
2544
- const cachedParentWasRemoved = Array.from(mutation.removedNodes).some((node) => {
2545
- var _a, _b;
2546
- const isDirectMatch = node === this.cachedOriginalParent;
2547
- const isContainedMatch = this.cachedOriginalParent
2548
- ? (_b = (_a = node).contains) === null || _b === void 0 ? void 0 : _b.call(_a, this.cachedOriginalParent)
2549
- : false;
2550
- return isDirectMatch || isContainedMatch;
2551
- });
2552
- // Also check if parent is no longer connected to DOM
2553
- const cachedParentDisconnected = this.cachedOriginalParent && !this.cachedOriginalParent.isConnected;
2554
- if (cachedParentWasRemoved || cachedParentDisconnected) {
2555
- this.dismiss(undefined, 'parent-removed');
2556
- // Release the reference to the cached original parent
2557
- // so we don't have a memory leak
2558
- this.cachedOriginalParent = undefined;
2559
- }
2560
- }
2561
- });
2562
- });
2563
- // Observe document body with subtree to catch removals at any level
2564
- this.parentRemovalObserver.observe(document.body, {
2565
- childList: true,
2566
- subtree: true,
2567
- });
2568
- }
2569
- cleanupParentRemovalObserver() {
2570
- var _a;
2571
- (_a = this.parentRemovalObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
2572
- this.parentRemovalObserver = undefined;
2573
- }
2574
- onDragStart() {
2575
- this.ionDragStart.emit();
2576
- }
2577
- onDragMove(detail) {
2578
- this.ionDragMove.emit(detail);
2579
- }
2580
- onDragEnd(detail) {
2581
- this.ionDragEnd.emit(detail);
2582
- }
2583
- render() {
2584
- const { handle, isSheetModal, presentingElement, htmlAttributes, handleBehavior, inheritedAttributes, focusTrap, expandToScroll, } = this;
2585
- const showHandle = handle !== false && isSheetModal;
2586
- const mode = getIonMode(this);
2587
- const isCardModal = presentingElement !== undefined && mode === 'ios';
2588
- const isHandleCycle = handleBehavior === 'cycle';
2589
- const isSheetModalWithHandle = isSheetModal && showHandle;
2590
- return (h(Host, Object.assign({ key: 'bca3cbdb2ce8e5127d27eae7494c434aaeddaf88', "no-router": true,
2591
- // Allow the modal to be navigable when the handle is focusable
2592
- tabIndex: isHandleCycle && isSheetModalWithHandle ? 0 : -1 }, htmlAttributes, { style: {
2593
- zIndex: `${20000 + this.overlayIndex}`,
2594
- }, class: Object.assign({ [mode]: true, ['modal-default']: !isCardModal && !isSheetModal, [`modal-card`]: isCardModal, [`modal-sheet`]: isSheetModal, [`modal-no-expand-scroll`]: isSheetModal && !expandToScroll, 'overlay-hidden': true, [FOCUS_TRAP_DISABLE_CLASS]: focusTrap === false }, getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle, onFocus: this.onModalFocus }), h("ion-backdrop", { key: 'b1c4112123d84d8a9b9d455bcc17d884f99d9f28', ref: (el) => (this.backdropEl = el), visible: this.showBackdrop, tappable: this.backdropDismiss, part: "backdrop" }), mode === 'ios' && h("div", { key: '080c8e6d37b311a1b5ad2655d99f18668abae211', class: "modal-shadow" }), h("div", Object.assign({ key: '8ba05e9520b1b5529bf0caeb766da5bf612d4d14',
2595
- /*
2596
- role and aria-modal must be used on the
2597
- same element. They must also be set inside the
2598
- shadow DOM otherwise ion-button will not be highlighted
2599
- when using VoiceOver: https://bugs.webkit.org/show_bug.cgi?id=247134
2600
- */
2601
- role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (h("button", { key: '2d2d5d731f55755f32ebcbf557f97486dc6202a6', class: "modal-handle",
2602
- // Prevents the handle from receiving keyboard focus when it does not cycle
2603
- tabIndex: !isHandleCycle ? -1 : 0, "aria-label": "Activate to adjust the size of the dialog overlaying the screen", onClick: isHandleCycle ? this.onHandleClick : undefined, part: "handle", ref: (el) => (this.dragHandleEl = el) })), h("slot", { key: 'c717d19865dafba02e15db79bc0662c5d89e96fd', onSlotchange: this.onSlotChange }))));
2604
- }
2605
- get el() { return this; }
2606
- static get watchers() { return {
2607
- "isOpen": ["onIsOpenChange"],
2608
- "trigger": ["triggerChanged"]
2609
- }; }
2610
- static get style() { return {
2611
- ios: modalIosCss,
2612
- md: modalMdCss
2613
- }; }
2614
- }, [289, "ion-modal", {
2615
- "hasController": [4, "has-controller"],
2616
- "overlayIndex": [2, "overlay-index"],
2617
- "delegate": [16],
2618
- "keyboardClose": [4, "keyboard-close"],
2619
- "enterAnimation": [16],
2620
- "leaveAnimation": [16],
2621
- "breakpoints": [16],
2622
- "expandToScroll": [4, "expand-to-scroll"],
2623
- "initialBreakpoint": [2, "initial-breakpoint"],
2624
- "backdropBreakpoint": [2, "backdrop-breakpoint"],
2625
- "handle": [4],
2626
- "handleBehavior": [1, "handle-behavior"],
2627
- "component": [1],
2628
- "componentProps": [16],
2629
- "cssClass": [1, "css-class"],
2630
- "backdropDismiss": [4, "backdrop-dismiss"],
2631
- "showBackdrop": [4, "show-backdrop"],
2632
- "animated": [4],
2633
- "presentingElement": [16],
2634
- "htmlAttributes": [16],
2635
- "isOpen": [4, "is-open"],
2636
- "trigger": [1],
2637
- "keepContentsMounted": [4, "keep-contents-mounted"],
2638
- "focusTrap": [4, "focus-trap"],
2639
- "canDismiss": [4, "can-dismiss"],
2640
- "isSheetModal": [32],
2641
- "presented": [32],
2642
- "present": [64],
2643
- "dismiss": [64],
2644
- "onDidDismiss": [64],
2645
- "onWillDismiss": [64],
2646
- "setCurrentBreakpoint": [64],
2647
- "getCurrentBreakpoint": [64]
2648
- }, [[9, "resize", "onWindowResize"]], {
2649
- "isOpen": ["onIsOpenChange"],
2650
- "trigger": ["triggerChanged"]
2651
- }]);
2652
- const LIFECYCLE_MAP = {
2653
- ionModalDidPresent: 'ionViewDidEnter',
2654
- ionModalWillPresent: 'ionViewWillEnter',
2655
- ionModalWillDismiss: 'ionViewWillLeave',
2656
- ionModalDidDismiss: 'ionViewDidLeave',
2657
- };
2658
- function defineCustomElement() {
2659
- if (typeof customElements === "undefined") {
2660
- return;
2661
- }
2662
- const components = ["ion-modal", "ion-backdrop"];
2663
- components.forEach(tagName => { switch (tagName) {
2664
- case "ion-modal":
2665
- if (!customElements.get(tagName)) {
2666
- customElements.define(tagName, Modal);
2667
- }
2668
- break;
2669
- case "ion-backdrop":
2670
- if (!customElements.get(tagName)) {
2671
- defineCustomElement$1();
2672
- }
2673
- break;
2674
- } });
2675
- }
2676
-
2677
- export { Modal as M, defineCustomElement as d };
4
+ import{proxyCustomElement as t,HTMLElement as o,createEvent as i,writeTask as a,h as e,Host as r,transformTag as s}from"@stencil/core/internal/client";import{a as n,i as d,d as h,r as l,f as p,p as c}from"./index8.js";import{C as m,a as f,d as u}from"./framework-delegate.js";import{f as b,g as v,r as x,d as w,k as g}from"./helpers.js";import{c as k}from"./lock-controller.js";import{p as y,c as A}from"./index4.js";import{g as Y}from"./capacitor.js";import{G as D,O as E,F as M,e as S,B,j as O,k as C,f as T,g as P,h as j}from"./overlays.js";import{g as $}from"./theme.js";import{e as I,w as R}from"./index2.js";import{b as L}from"./ionic-global.js";import{KEYBOARD_DID_OPEN as z}from"./keyboard.js";import{c as N}from"./animation.js";import{g as W}from"./cubic-bezier.js";import{createGesture as H}from"./index3.js";import{w as V}from"./index9.js";import{d as F}from"./backdrop.js";var K;!function(t){t.Dark="DARK",t.Light="LIGHT",t.Default="DEFAULT"}(K||(K={}));const Z={getEngine(){const t=Y();if(null==t?void 0:t.isPluginAvailable("StatusBar"))return t.Plugins.StatusBar},setStyle(t){const o=this.getEngine();o&&o.setStyle(t)},getStyle:async function(){const t=this.getEngine();if(!t)return K.Default;const{style:o}=await t.getInfo();return o}},G=(t,o)=>{if(1===o)return 0;const i=1/(1-o);return t*i+-o*i},U=()=>{!V||V.innerWidth>=768||Z.setStyle({style:K.Dark})},_=(t=K.Default)=>{!V||V.innerWidth>=768||Z.setStyle({style:t})},q=async(t,o)=>{"function"==typeof t.canDismiss&&await t.canDismiss(void 0,D)&&(o.isRunning()?o.onFinish((()=>{t.dismiss(void 0,"handler")}),{oneTimeCallback:!0}):t.dismiss(void 0,"handler"))},J=t=>.00255275*2.71828**(-14.9619*t)-1.00255*2.71828**(-.0380968*t)+1,Q=.915,X=(t,o)=>b(400,t/Math.abs(1.1*o),500),tt=(t,o)=>{const i=window.innerHeight,a=t.getBoundingClientRect().top,e=Math.round(1e3*(1-o/(i-a)))/1e3;return Math.max(0,Math.min(1,e))},ot=t=>{const{currentBreakpoint:o,backdropBreakpoint:i,expandToScroll:a}=t,e=void 0===i||i<o,r=e?`calc(var(--backdrop-opacity) * ${o})`:"0",s=N("backdropAnimation").fromTo("opacity",0,r);return e&&s.beforeStyles({"pointer-events":"none"}).afterClearStyles(["pointer-events"]),{wrapperAnimation:N("wrapperAnimation").keyframes([{offset:0,opacity:1,transform:"translateY(100%)"},{offset:1,opacity:1,transform:`translateY(${100-100*o}%)`}]),backdropAnimation:s,contentAnimation:a?void 0:N("contentAnimation").keyframes([{offset:0,opacity:1,maxHeight:100*(1-o)+"%"},{offset:1,opacity:1,maxHeight:100*o+"%"}])}},it=t=>{const{currentBreakpoint:o,backdropBreakpoint:i}=t,a=`calc(var(--backdrop-opacity) * ${G(o,i)})`,e=[{offset:0,opacity:a},{offset:1,opacity:0}],r=[{offset:0,opacity:a},{offset:i,opacity:0},{offset:1,opacity:0}],s=N("backdropAnimation").keyframes(0!==i?r:e);return{wrapperAnimation:N("wrapperAnimation").keyframes([{offset:0,opacity:1,transform:`translateY(${100-100*o}%)`},{offset:1,opacity:1,transform:"translateY(100%)"}]),backdropAnimation:s}},at=(t,o)=>{const{presentingEl:i,currentBreakpoint:a,expandToScroll:e}=o,r=v(t),{wrapperAnimation:s,backdropAnimation:n,contentAnimation:d}=void 0!==a?ot(o):{backdropAnimation:N().fromTo("opacity",.01,"var(--backdrop-opacity)").beforeStyles({"pointer-events":"none"}).afterClearStyles(["pointer-events"]),wrapperAnimation:N().fromTo("transform","translateY(100vh)","translateY(0vh)"),contentAnimation:void 0};n.addElement(r.querySelector("ion-backdrop")),s.addElement(r.querySelectorAll(".modal-wrapper, .modal-shadow")).beforeStyles({opacity:1}),!e&&(null==d||d.addElement(t.querySelector(".ion-page")));const h=N("entering-base").addElement(t).easing("cubic-bezier(0.32,0.72,0,1)").duration(500).addAnimation([s]);if(d&&h.addAnimation(d),i){const t=window.innerWidth<768,o="ION-MODAL"===i.tagName&&void 0!==i.presentingElement,a=v(i),e=N().beforeStyles({transform:"translateY(0)","transform-origin":"top center",overflow:"hidden"}),r=document.body;if(t){const t=CSS.supports("width","max(0px, 1px)")?"max(30px, var(--ion-safe-area-top))":"30px",a=`translateY(${o?"-10px":t}) scale(0.915)`;e.afterStyles({transform:a}).beforeAddWrite((()=>r.style.setProperty("background-color","black"))).addElement(i).keyframes([{offset:0,filter:"contrast(1)",transform:"translateY(0px) scale(1)",borderRadius:"0px"},{offset:1,filter:"contrast(0.85)",transform:a,borderRadius:"10px 10px 0 0"}]),h.addAnimation(e)}else if(h.addAnimation(n),o){const t=`translateY(-10px) scale(${o?Q:1})`;e.afterStyles({transform:t}).addElement(a.querySelector(".modal-wrapper")).keyframes([{offset:0,filter:"contrast(1)",transform:"translateY(0) scale(1)"},{offset:1,filter:"contrast(0.85)",transform:t}]);const i=N().afterStyles({transform:t}).addElement(a.querySelector(".modal-shadow")).keyframes([{offset:0,opacity:"1",transform:"translateY(0) scale(1)"},{offset:1,opacity:"0",transform:t}]);h.addAnimation([e,i])}else s.fromTo("opacity","0","1")}else h.addAnimation(n);return h},et=(t,o,i=500)=>{const{presentingEl:a,currentBreakpoint:e}=o,r=v(t),{wrapperAnimation:s,backdropAnimation:n}=void 0!==e?it(o):{backdropAnimation:N().fromTo("opacity","var(--backdrop-opacity)",0),wrapperAnimation:N().fromTo("transform","translateY(0vh)","translateY(100vh)")};n.addElement(r.querySelector("ion-backdrop")),s.addElement(r.querySelectorAll(".modal-wrapper, .modal-shadow")).beforeStyles({opacity:1});const d=N("leaving-base").addElement(t).easing("cubic-bezier(0.32,0.72,0,1)").duration(i).addAnimation(s);if(a){const t=window.innerWidth<768,o="ION-MODAL"===a.tagName&&void 0!==a.presentingElement,i=v(a),e=N().beforeClearStyles(["transform"]).afterClearStyles(["transform"]).onFinish((t=>{1===t&&(a.style.setProperty("overflow",""),Array.from(r.querySelectorAll("ion-modal:not(.overlay-hidden)")).filter((t=>void 0!==t.presentingElement)).length<=1&&r.style.setProperty("background-color",""))})),r=document.body;if(t){const t=CSS.supports("width","max(0px, 1px)")?"max(30px, var(--ion-safe-area-top))":"30px",i=`translateY(${o?"-10px":t}) scale(0.915)`;e.addElement(a).keyframes([{offset:0,filter:"contrast(0.85)",transform:i,borderRadius:"10px 10px 0 0"},{offset:1,filter:"contrast(1)",transform:"translateY(0px) scale(1)",borderRadius:"0px"}]),d.addAnimation(e)}else if(d.addAnimation(n),o){const t=`translateY(-10px) scale(${o?Q:1})`;e.addElement(i.querySelector(".modal-wrapper")).afterStyles({transform:"translate3d(0, 0, 0)"}).keyframes([{offset:0,filter:"contrast(0.85)",transform:t},{offset:1,filter:"contrast(1)",transform:"translateY(0) scale(1)"}]);const a=N().addElement(i.querySelector(".modal-shadow")).afterStyles({transform:"translateY(0) scale(1)"}).keyframes([{offset:0,opacity:"0",transform:t},{offset:1,opacity:"1",transform:"translateY(0) scale(1)"}]);d.addAnimation([e,a])}else s.fromTo("opacity","1","0")}else d.addAnimation(n);return d},rt=(t,o)=>{const{currentBreakpoint:i,expandToScroll:a}=o,e=v(t),{wrapperAnimation:r,backdropAnimation:s,contentAnimation:n}=void 0!==i?ot(o):{backdropAnimation:N().fromTo("opacity",.01,"var(--backdrop-opacity)").beforeStyles({"pointer-events":"none"}).afterClearStyles(["pointer-events"]),wrapperAnimation:N().keyframes([{offset:0,opacity:.01,transform:"translateY(40px)"},{offset:1,opacity:1,transform:"translateY(0px)"}]),contentAnimation:void 0};s.addElement(e.querySelector("ion-backdrop")),r.addElement(e.querySelector(".modal-wrapper")),!a&&(null==n||n.addElement(t.querySelector(".ion-page")));const d=N().addElement(t).easing("cubic-bezier(0.36,0.66,0.04,1)").duration(280).addAnimation([s,r]);return n&&d.addAnimation(n),d},st=(t,o)=>{const{currentBreakpoint:i}=o,a=v(t),{wrapperAnimation:e,backdropAnimation:r}=void 0!==i?it(o):{backdropAnimation:N().fromTo("opacity","var(--backdrop-opacity)",0),wrapperAnimation:N().keyframes([{offset:0,opacity:.99,transform:"translateY(0px)"},{offset:1,opacity:0,transform:"translateY(40px)"}])};return r.addElement(a.querySelector("ion-backdrop")),e.addElement(a.querySelector(".modal-wrapper")),N().easing("cubic-bezier(0.47,0,0.745,0.715)").duration(200).addAnimation([r,e])},nt=t(class extends o{constructor(t){super(),!1!==t&&this.__registerHost(),this.__attachShadow(),this.didPresent=i(this,"ionModalDidPresent",7),this.willPresent=i(this,"ionModalWillPresent",7),this.willDismiss=i(this,"ionModalWillDismiss",7),this.didDismiss=i(this,"ionModalDidDismiss",7),this.ionBreakpointDidChange=i(this,"ionBreakpointDidChange",7),this.didPresentShorthand=i(this,"didPresent",7),this.willPresentShorthand=i(this,"willPresent",7),this.willDismissShorthand=i(this,"willDismiss",7),this.didDismissShorthand=i(this,"didDismiss",7),this.ionMount=i(this,"ionMount",7),this.ionDragStart=i(this,"ionDragStart",7),this.ionDragMove=i(this,"ionDragMove",7),this.ionDragEnd=i(this,"ionDragEnd",7),this.lockController=k(),this.triggerController=S(),this.coreDelegate=m(),this.isSheetModal=!1,this.inheritedAttributes={},this.inline=!1,this.gestureAnimationDismissing=!1,this.presented=!1,this.hasController=!1,this.keyboardClose=!0,this.expandToScroll=!0,this.backdropBreakpoint=0,this.handleBehavior="none",this.backdropDismiss=!0,this.showBackdrop=!0,this.animated=!0,this.isOpen=!1,this.keepContentsMounted=!1,this.focusTrap=!0,this.canDismiss=!0,this.onHandleClick=()=>{const{sheetTransition:t,handleBehavior:o}=this;"cycle"===o&&void 0===t&&this.moveToNextBreakpoint()},this.onBackdropTap=()=>{const{sheetTransition:t}=this;void 0===t&&this.dismiss(void 0,B)},this.onLifecycle=t=>{const o=this.usersElement,i=dt[t.type];if(o&&i){const a=new CustomEvent(i,{bubbles:!1,cancelable:!1,detail:t.detail});o.dispatchEvent(a)}},this.onModalFocus=t=>{const{dragHandleEl:o,el:i}=this;t.target===i&&o&&-1!==o.tabIndex&&o.focus()},this.onSlotChange=({target:t})=>{t.assignedElements().forEach((t=>{t.querySelectorAll("ion-modal").forEach((t=>{null===t.getAttribute("data-parent-ion-modal")&&t.setAttribute("data-parent-ion-modal",this.el.id)}))}))}}onIsOpenChange(t,o){!0===t&&!1===o?this.present():!1===t&&!0===o&&this.dismiss()}triggerChanged(){const{trigger:t,el:o,triggerController:i}=this;t&&i.addClickListener(o,t)}onWindowResize(){"ios"!==L(this)||!this.presentingElement||this.enterAnimation||this.leaveAnimation||(clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout((()=>{this.handleViewTransition()}),50))}breakpointsChanged(t){void 0!==t&&(this.sortedBreakpoints=t.sort(((t,o)=>t-o)))}connectedCallback(){const{el:t}=this;O(t),this.triggerChanged()}disconnectedCallback(){this.triggerController.removeClickListener(),this.cleanupViewTransitionListener(),this.cleanupParentRemovalObserver()}componentWillLoad(){var t;const{breakpoints:o,initialBreakpoint:i,el:a,htmlAttributes:e}=this,r=this.isSheetModal=void 0!==o&&void 0!==i,s=["aria-label","role"];this.inheritedAttributes=w(a,s),a.parentNode&&(this.cachedOriginalParent=a.parentNode),void 0!==e&&s.forEach((t=>{e[t]&&(this.inheritedAttributes=Object.assign(Object.assign({},this.inheritedAttributes),{[t]:e[t]}),delete e[t])})),r&&(this.currentBreakpoint=this.initialBreakpoint),void 0===o||void 0===i||o.includes(i)||y("[ion-modal] - Your breakpoints array must include the initialBreakpoint value."),(null===(t=this.htmlAttributes)||void 0===t?void 0:t.id)||C(this.el)}componentDidLoad(){!0===this.isOpen&&x((()=>this.present())),this.breakpointsChanged(this.breakpoints),this.triggerChanged()}getDelegate(t=!1){if(this.workingDelegate&&!t)return{delegate:this.workingDelegate,inline:this.inline};const o=this.inline=null!==this.el.parentNode&&!this.hasController;return{inline:o,delegate:this.workingDelegate=o?this.delegate||this.coreDelegate:this.delegate}}async checkCanDismiss(t,o){const{canDismiss:i}=this;return"function"==typeof i?i(t,o):i}async present(){const t=await this.lockController.lock();if(this.presented)return void t();const{presentingElement:o,el:i}=this;this.currentBreakpoint=this.initialBreakpoint;const{inline:e,delegate:r}=this.getDelegate(!0);this.ionMount.emit(),this.usersElement=await f(r,i,this.component,["ion-page"],this.componentProps,e),g(i)?await I(this.usersElement):this.keepContentsMounted||await R(),a((()=>this.el.classList.add("show-modal")));const s=void 0!==o;s&&"ios"===L(this)&&(this.statusBarStyle=await Z.getStyle(),U()),await T(this,"modalEnter",at,rt,{presentingEl:o,currentBreakpoint:this.initialBreakpoint,backdropBreakpoint:this.backdropBreakpoint,expandToScroll:this.expandToScroll}),"undefined"!=typeof window&&(this.keyboardOpenCallback=()=>{this.gesture&&(this.gesture.enable(!1),x((()=>{this.gesture&&this.gesture.enable(!0)})))},window.addEventListener(z,this.keyboardOpenCallback));const n=void 0!==this.breakpoints&&void 0!==this.initialBreakpoint;this.isSheetModal=n,n?this.initSheetGesture():s&&this.initSwipeToClose(),this.initViewTransitionListener(),this.initParentRemovalObserver(),t()}initSwipeToClose(){var t;if("ios"!==L(this))return;const{el:o}=this,i=this.leaveAnimation||A.get("modalLeave",et),a=this.animation=i(o,{presentingEl:this.presentingElement,expandToScroll:this.expandToScroll});if(!p(o))return void c(o);const e=null!==(t=this.statusBarStyle)&&void 0!==t?t:K.Default;this.gesture=((t,o,i,a,e,r,s)=>{const p=.5,c=t.offsetHeight;let m=!1,f=!1,u=null,x=null,w=!0,g=0;const k=H({el:t,gestureName:"modalSwipeToClose",gesturePriority:E,direction:"y",threshold:10,canStart:t=>{const o=t.event.target;if(null===o||!o.closest)return!0;if(u=n(o),u){if(d(u)){const t=v(u);x=t.querySelector(".inner-scroll")}else x=u;return!u.querySelector("ion-refresher")&&0===x.scrollTop}return null===o.closest("ion-footer")},onStart:i=>{const{deltaY:a}=i;w=!u||!d(u)||u.scrollY,f=void 0!==t.canDismiss&&!0!==t.canDismiss,a>0&&u&&h(u),o.progressStart(!0,m?1:0),e()},onMove:a=>{const{deltaY:e}=a;e>0&&u&&h(u);const s=a.deltaY/c,n=s>=0&&f,d=n?.2:.9999,l=n?J(s/d):s,m=b(1e-4,l,d);o.progressStep(m),m>=p&&g<p?_(i):m<p&&g>=p&&U(),g=m;const v={currentY:a.currentY,deltaY:a.deltaY,velocityY:a.velocityY,progress:tt(t,a.deltaY)};r(v)},onEnd:i=>{const e=i.velocityY,r=i.deltaY/c,n=r>=0&&f,d=n?.2:.9999,h=n?J(r/d):r,v=b(1e-4,h,d),x=!n&&(i.deltaY+1e3*e)/c>=p;let g=x?-.001:.001;x?(o.easing("cubic-bezier(0.32, 0.72, 0, 1)"),g+=W([0,0],[.32,.72],[0,1],[1,1],v)[0]):(o.easing("cubic-bezier(1, 0, 0.68, 0.28)"),g+=W([0,0],[1,0],[.68,.28],[1,1],v)[0]);const y=X(x?r*c:(1-v)*c,e);m=x,k.enable(!1),u&&l(u,w),o.onFinish((()=>{x||k.enable(!0)})).progressEnd(x?1:0,g,y),n&&v>d/4?q(t,o):x&&a();const A={currentY:i.currentY,deltaY:i.deltaY,velocityY:i.velocityY,progress:tt(t,i.deltaY)};s(A)}});return k})(o,a,e,(()=>this.cardOnDismiss()),(()=>this.onDragStart()),(t=>this.onDragMove(t)),(t=>this.onDragEnd(t))),this.gesture.enable(!0)}initSheetGesture(){const{wrapperEl:t,initialBreakpoint:o,backdropBreakpoint:i}=this;if(!t||void 0===o)return;const a=this.enterAnimation||A.get("modalEnter",at),e=this.animation=a(this.el,{presentingEl:this.presentingElement,currentBreakpoint:o,backdropBreakpoint:i,expandToScroll:this.expandToScroll});e.progressStart(!0,1);const{gesture:r,moveSheetToBreakpoint:s}=((t,o,i,a,e,r,s=[],h,l,p,c,m,f,u)=>{const w={WRAPPER_KEYFRAMES:[{offset:0,transform:"translateY(0%)"},{offset:1,transform:"translateY(100%)"}],BACKDROP_KEYFRAMES:0!==e?[{offset:0,opacity:"var(--backdrop-opacity)"},{offset:1-e,opacity:0},{offset:1,opacity:0}]:[{offset:0,opacity:"var(--backdrop-opacity)"},{offset:1,opacity:.01}],CONTENT_KEYFRAMES:[{offset:0,maxHeight:"100%"},{offset:1,maxHeight:"0%"}]},g=t.querySelector("ion-content"),k=i.clientHeight;let y=a,A=0,Y=!1,D=null,E=null,S=null,B=null;const O=s[s.length-1],C=s[0],T=r.childAnimations.find((t=>"wrapperAnimation"===t.id)),P=r.childAnimations.find((t=>"backdropAnimation"===t.id)),j=r.childAnimations.find((t=>"contentAnimation"===t.id)),$=()=>{!1!==t.focusTrap&&!1!==t.showBackdrop&&(t.style.setProperty("pointer-events","auto"),o.style.setProperty("pointer-events","auto"),t.classList.remove(M))},I=()=>{t.style.setProperty("pointer-events","none"),o.style.setProperty("pointer-events","none"),t.classList.add(M)},R=o=>{if(!E&&(E=Array.from(t.querySelectorAll("ion-footer")),!E.length))return;const i=t.querySelector(".ion-page");if(B=o,"stationary"===o)E.forEach((t=>{t.classList.remove("modal-footer-moving"),t.style.removeProperty("position"),t.style.removeProperty("width"),t.style.removeProperty("height"),t.style.removeProperty("top"),t.style.removeProperty("left"),null==i||i.style.removeProperty("padding-bottom"),null==i||i.appendChild(t)}));else{let o=0;E.forEach(((i,a)=>{const e=i.getBoundingClientRect(),r=document.body.getBoundingClientRect();o+=i.clientHeight;const s=e.top-r.top,n=e.left-r.left;if(i.style.setProperty("--pinned-width",`${i.clientWidth}px`),i.style.setProperty("--pinned-height",`${i.clientHeight}px`),i.style.setProperty("--pinned-top",`${s}px`),i.style.setProperty("--pinned-left",`${n}px`),0===a){S=s;const o=t.querySelector("ion-header");o&&(S-=o.clientHeight)}})),E.forEach((t=>{null==i||i.style.setProperty("padding-bottom",`${o}px`),t.classList.add("modal-footer-moving"),t.style.setProperty("position","absolute"),t.style.setProperty("width","var(--pinned-width)"),t.style.setProperty("height","var(--pinned-height)"),t.style.setProperty("top","var(--pinned-top)"),t.style.setProperty("left","var(--pinned-left)"),document.body.appendChild(t)}))}};T&&P&&(T.keyframes([...w.WRAPPER_KEYFRAMES]),P.keyframes([...w.BACKDROP_KEYFRAMES]),null==j||j.keyframes([...w.CONTENT_KEYFRAMES]),r.progressStart(!0,1-y),y>e&&!1!==t.focusTrap&&!1!==t.showBackdrop?$():I()),g&&y!==O&&h&&(g.scrollY=!1);const L=o=>{const{breakpoint:i,canDismiss:a,breakpointOffset:n,animated:d}=o,l=a&&0===i,m=l?y:i,f=0!==m;return y=0,T&&P&&(T.keyframes([{offset:0,transform:`translateY(${100*n}%)`},{offset:1,transform:`translateY(${100*(1-m)}%)`}]),P.keyframes([{offset:0,opacity:`calc(var(--backdrop-opacity) * ${G(1-n,e)})`},{offset:1,opacity:`calc(var(--backdrop-opacity) * ${G(m,e)})`}]),j&&j.keyframes([{offset:0,maxHeight:100*(1-n)+"%"},{offset:1,maxHeight:100*m+"%"}]),r.progressStep(0)),V.enable(!1),l?q(t,r):f||p(),!g||m!==s[s.length-1]&&h||(g.scrollY=!0),h||0!==m||R("stationary"),new Promise((o=>{r.onFinish((()=>{f?(h||R("stationary"),T&&P?x((()=>{T.keyframes([...w.WRAPPER_KEYFRAMES]),P.keyframes([...w.BACKDROP_KEYFRAMES]),null==j||j.keyframes([...w.CONTENT_KEYFRAMES]),r.progressStart(!0,1-m),y=m,c(y),y>e&&!1!==t.focusTrap&&!1!==t.showBackdrop?$():I(),V.enable(!0),o()})):(V.enable(!0),o())):o()}),{oneTimeCallback:!0}).progressEnd(1,0,d?500:0)}))},z=t=>{const o=i.getBoundingClientRect().top+t,a=N(o);return s.reduce(((t,o)=>Math.abs(o-a)<Math.abs(t-a)?o:t))},N=t=>{const o=s[s.length-1],i=W(s[0]),a=W(o),e=Math.round((i-t)/(i-a)*1e3)/1e3;return Math.max(0,Math.min(1,e))},W=o=>{const i=t.getBoundingClientRect();return window.innerHeight-i.height*o},V=H({el:i,gestureName:"modalSheet",gesturePriority:40,direction:"y",threshold:10,canStart:t=>{const o=n(t.event.target);if(y=l(),!h&&o)return 0===(d(o)?v(o).querySelector(".inner-scroll"):o).scrollTop;if(1===y&&o){const t=d(o)?v(o).querySelector(".inner-scroll"):o;return!o.querySelector("ion-refresher")&&0===t.scrollTop}return!0},onStart:o=>{if(Y=void 0!==t.canDismiss&&!0!==t.canDismiss&&0===C,!h){const t=n(o.event.target);D=t&&d(t)?v(t).querySelector(".inner-scroll"):t}h||R("moving"),o.deltaY>0&&g&&(g.scrollY=!1),x((()=>{t.focus()})),r.progressStart(!0,1-y),m()},onMove:t=>{if(h||null===S||null===B||(t.currentY>=S&&"moving"===B?R("stationary"):t.currentY<S&&"stationary"===B&&R("moving")),!h&&t.deltaY<=0&&D)return;t.deltaY>0&&g&&(g.scrollY=!1);const o=s.length>1?1-s[1]:void 0,i=1-y+t.deltaY/k,a=void 0!==o&&i>=o&&Y,e=a?.95:.9999,n=a&&void 0!==o?o+J((i-o)/(e-o)):i;A=b(1e-4,n,e),r.progressStep(A);const d=z(t.deltaY),l={currentY:t.currentY,deltaY:t.deltaY,velocityY:t.velocityY,progress:N(t.currentY),snapBreakpoint:d};f(l)},onEnd:t=>{const o=z(t.deltaY),i={currentY:t.currentY,deltaY:t.deltaY,velocityY:t.velocityY,progress:N(t.currentY),snapBreakpoint:o};if(!h&&t.deltaY<=0&&D&&D.scrollTop>0)return R("stationary"),void u(i);L({breakpoint:o,breakpointOffset:A,canDismiss:Y,animated:!0}),u(i)}});return{gesture:V,moveSheetToBreakpoint:L}})(this.el,this.backdropEl,t,o,i,e,this.sortedBreakpoints,this.expandToScroll,(()=>{var t;return null!==(t=this.currentBreakpoint)&&void 0!==t?t:0}),(()=>this.sheetOnDismiss()),(t=>{this.currentBreakpoint!==t&&(this.currentBreakpoint=t,this.ionBreakpointDidChange.emit({breakpoint:t}))}),(()=>this.onDragStart()),(t=>this.onDragMove(t)),(t=>this.onDragEnd(t)));this.gesture=r,this.moveSheetToBreakpoint=s,this.gesture.enable(!0),(!1===this.showBackdrop||!1===this.focusTrap||i>0)&&this.setupChildRoutePassthrough()}setupChildRoutePassthrough(){var t;this.cachedPageParent=this.getOriginalPageParent();const i=this.cachedPageParent;if(!i||"ION-APP"===i.tagName)return;const a=Array.from(i.children).some((t=>{var i;return!(t===this.el||t instanceof o&&"none"===window.getComputedStyle(t).display||"TEMPLATE"===t.tagName||"SLOT"===t.tagName||t.nodeType===Node.TEXT_NODE&&!(null===(i=t.textContent)||void 0===i?void 0:i.trim()))}));if(a)return;i.classList.add("ion-page-overlay-passthrough");const e=i.parentElement;"ION-ROUTER-OUTLET"===(null==e?void 0:e.tagName)&&"ION-APP"!==(null===(t=e.parentElement)||void 0===t?void 0:t.tagName)&&(e.style.setProperty("pointer-events","none"),e.setAttribute("data-overlay-passthrough","true"))}getOriginalPageParent(){if(!this.cachedOriginalParent)return null;let t=this.cachedOriginalParent;for(;t&&!t.classList.contains("ion-page");)t=t.parentElement;return t}cleanupChildRoutePassthrough(){const t=this.cachedPageParent;if(!t)return;t.classList.remove("ion-page-overlay-passthrough");const o=t.parentElement;(null==o?void 0:o.hasAttribute("data-overlay-passthrough"))&&(o.style.removeProperty("pointer-events"),o.removeAttribute("data-overlay-passthrough")),this.cachedPageParent=void 0}sheetOnDismiss(){this.gestureAnimationDismissing=!0,this.animation.onFinish((async()=>{this.currentBreakpoint=0,this.ionBreakpointDidChange.emit({breakpoint:this.currentBreakpoint}),await this.dismiss(void 0,D),this.gestureAnimationDismissing=!1}))}cardOnDismiss(){this.gestureAnimationDismissing=!0,_(this.statusBarStyle),this.animation.onFinish((async()=>{await this.dismiss(void 0,D),this.gestureAnimationDismissing=!1}))}async dismiss(t,o){var i;if(this.gestureAnimationDismissing&&o!==D)return!1;const e=await this.lockController.lock();if(await this.dismissNestedModals(),"handler"!==o&&!await this.checkCanDismiss(t,o))return e(),!1;const{presentingElement:r}=this;void 0!==r&&"ios"===L(this)&&_(this.statusBarStyle),"undefined"!=typeof window&&this.keyboardOpenCallback&&(window.removeEventListener(z,this.keyboardOpenCallback),this.keyboardOpenCallback=void 0);const s=await P(this,t,o,"modalLeave",et,st,{presentingEl:r,currentBreakpoint:null!==(i=this.currentBreakpoint)&&void 0!==i?i:this.initialBreakpoint,backdropBreakpoint:this.backdropBreakpoint,expandToScroll:this.expandToScroll});if(s){const{delegate:t}=this.getDelegate();await u(t,this.usersElement),a((()=>this.el.classList.remove("show-modal"))),this.animation&&this.animation.destroy(),this.gesture&&this.gesture.destroy(),this.cleanupViewTransitionListener(),this.cleanupParentRemovalObserver(),this.cleanupChildRoutePassthrough()}return this.currentBreakpoint=void 0,this.animation=void 0,e(),s}onDidDismiss(){return j(this.el,"ionModalDidDismiss")}onWillDismiss(){return j(this.el,"ionModalWillDismiss")}async setCurrentBreakpoint(t){if(!this.isSheetModal)return void y("[ion-modal] - setCurrentBreakpoint is only supported on sheet modals.");if(!this.breakpoints.includes(t))return void y(`[ion-modal] - Attempted to set invalid breakpoint value ${t}. Please double check that the breakpoint value is part of your defined breakpoints.`);const{currentBreakpoint:o,moveSheetToBreakpoint:i,canDismiss:a,breakpoints:e,animated:r}=this;o!==t&&i&&(this.sheetTransition=i({breakpoint:t,breakpointOffset:1-o,canDismiss:void 0!==a&&!0!==a&&0===e[0],animated:r}),await this.sheetTransition,this.sheetTransition=void 0)}async getCurrentBreakpoint(){return this.currentBreakpoint}async moveToNextBreakpoint(){const{breakpoints:t,currentBreakpoint:o}=this;if(!t||null==o)return!1;const i=t.filter((t=>0!==t)),a=i.indexOf(o),e=i[(a+1)%i.length];return await this.setCurrentBreakpoint(e),!0}initViewTransitionListener(){"ios"!==L(this)||!this.presentingElement||this.enterAnimation||this.leaveAnimation||(this.currentViewIsPortrait=window.innerWidth<768)}handleViewTransition(){if(!this.presented)return;const t=window.innerWidth<768;if(this.currentViewIsPortrait===t)return;this.viewTransitionAnimation&&(this.viewTransitionAnimation.destroy(),this.viewTransitionAnimation=void 0);const{presentingElement:o}=this;if(!o)return;let i;i=this.currentViewIsPortrait&&!t?((t,o,i=300)=>{const{presentingEl:a}=o;if(!a)return N("portrait-to-landscape-transition");const e="ION-MODAL"===a.tagName&&void 0!==a.presentingElement,r=v(a),s=document.body,n=N("portrait-to-landscape-transition").addElement(t).easing("cubic-bezier(0.32,0.72,0,1)").duration(i),d=N().beforeStyles({transform:"translateY(0)","transform-origin":"top center",overflow:"hidden"});if(e){const t="translateY(-10px) scale(0.915)",o="translateY(0px) scale(1)";d.addElement(a).afterStyles({transform:o}).fromTo("transform",t,o).fromTo("filter","contrast(0.85)","contrast(1)");const i=N().addElement(r.querySelector(".modal-shadow")).afterStyles({transform:o,opacity:"0"}).fromTo("transform",t,o);n.addAnimation([d,i])}else{const o=v(t),i=N().addElement(o.querySelectorAll(".modal-wrapper, .modal-shadow")).fromTo("opacity","1","1"),e=N().addElement(o.querySelector("ion-backdrop")).fromTo("opacity","var(--backdrop-opacity)","var(--backdrop-opacity)"),r=`translateY(${CSS.supports("width","max(0px, 1px)")?"max(30px, var(--ion-safe-area-top))":"30px"}) scale(0.915)`;d.addElement(a).afterStyles({transform:"translateY(0px) scale(1)","border-radius":"0px"}).beforeAddWrite((()=>s.style.setProperty("background-color",""))).fromTo("transform",r,"translateY(0px) scale(1)").fromTo("filter","contrast(0.85)","contrast(1)").fromTo("border-radius","10px 10px 0 0","0px"),n.addAnimation([d,i,e])}return n})(this.el,{presentingEl:o}):((t,o,i=300)=>{const{presentingEl:a}=o;if(!a)return N("landscape-to-portrait-transition");const e="ION-MODAL"===a.tagName&&void 0!==a.presentingElement,r=v(a),s=document.body,n=N("landscape-to-portrait-transition").addElement(t).easing("cubic-bezier(0.32,0.72,0,1)").duration(i),d=N().beforeStyles({transform:"translateY(0)","transform-origin":"top center",overflow:"hidden"});if(e){const t="translateY(-10px) scale(0.915)",o="translateY(0) scale(1)";d.addElement(a).afterStyles({transform:o}).fromTo("transform",t,o);const i=N().addElement(r.querySelector(".modal-shadow")).afterStyles({transform:o,opacity:"0"}).fromTo("transform",t,o);n.addAnimation([d,i])}else{const o=v(t),i=N().addElement(o.querySelectorAll(".modal-wrapper, .modal-shadow")).fromTo("opacity","1","1"),e=N().addElement(o.querySelector("ion-backdrop")).fromTo("opacity","var(--backdrop-opacity)","var(--backdrop-opacity)"),r=`translateY(${CSS.supports("width","max(0px, 1px)")?"max(30px, var(--ion-safe-area-top))":"30px"}) scale(0.915)`;d.addElement(a).afterStyles({transform:r}).beforeAddWrite((()=>s.style.setProperty("background-color","black"))).keyframes([{offset:0,transform:"translateY(0px) scale(1)",filter:"contrast(1)",borderRadius:"0px"},{offset:.2,transform:"translateY(0px) scale(1)",filter:"contrast(1)",borderRadius:"10px 10px 0 0"},{offset:1,transform:r,filter:"contrast(0.85)",borderRadius:"10px 10px 0 0"}]),n.addAnimation([d,i,e])}return n})(this.el,{presentingEl:o}),this.currentViewIsPortrait=t,this.viewTransitionAnimation=i,i.play().then((()=>{this.viewTransitionAnimation=void 0,this.reinitSwipeToClose()}))}cleanupViewTransitionListener(){this.resizeTimeout&&(clearTimeout(this.resizeTimeout),this.resizeTimeout=void 0),this.viewTransitionAnimation&&(this.viewTransitionAnimation.destroy(),this.viewTransitionAnimation=void 0)}reinitSwipeToClose(){"ios"===L(this)&&this.presentingElement&&(this.gesture&&(this.gesture.destroy(),this.gesture=void 0),this.animation&&(this.animation.progressEnd(0,0,0),this.animation.destroy(),this.animation=void 0),x((()=>{this.ensureCorrectModalPosition(),this.initSwipeToClose()})))}ensureCorrectModalPosition(){const{el:t,presentingElement:o}=this,i=v(t).querySelector(".modal-wrapper");if(i&&(i.style.transform="translateY(0vh)",i.style.opacity="1"),"ION-MODAL"===(null==o?void 0:o.tagName))if(window.innerWidth<768){const t=CSS.supports("width","max(0px, 1px)")?"max(30px, var(--ion-safe-area-top))":"30px";o.style.transform=`translateY(${t}) scale(0.915)`}else o.style.transform="translateY(0px) scale(1)"}async dismissNestedModals(){const t=document.querySelectorAll(`ion-modal[data-parent-ion-modal="${this.el.id}"]`);null==t||t.forEach((async t=>{await t.dismiss(void 0,"parent-dismissed")}))}initParentRemovalObserver(){"undefined"!=typeof MutationObserver&&"undefined"!=typeof window&&this.cachedOriginalParent&&this.cachedOriginalParent.nodeType!==Node.DOCUMENT_NODE&&this.cachedOriginalParent.nodeType!==Node.DOCUMENT_FRAGMENT_NODE&&(this.hasController||this.cachedOriginalParent===document.body||"ION-APP"===this.cachedOriginalParent.tagName||(this.parentRemovalObserver=new MutationObserver((t=>{t.forEach((t=>{"childList"===t.type&&t.removedNodes.length>0&&(Array.from(t.removedNodes).some((t=>{var o,i;const a=t===this.cachedOriginalParent,e=!!this.cachedOriginalParent&&(null===(i=(o=t).contains)||void 0===i?void 0:i.call(o,this.cachedOriginalParent));return a||e}))||this.cachedOriginalParent&&!this.cachedOriginalParent.isConnected)&&(this.dismiss(void 0,"parent-removed"),this.cachedOriginalParent=void 0)}))})),this.parentRemovalObserver.observe(document.body,{childList:!0,subtree:!0})))}cleanupParentRemovalObserver(){var t;null===(t=this.parentRemovalObserver)||void 0===t||t.disconnect(),this.parentRemovalObserver=void 0}onDragStart(){this.ionDragStart.emit()}onDragMove(t){this.ionDragMove.emit(t)}onDragEnd(t){this.ionDragEnd.emit(t)}render(){const{handle:t,isSheetModal:o,presentingElement:i,htmlAttributes:a,handleBehavior:s,inheritedAttributes:n,focusTrap:d,expandToScroll:h}=this,l=!1!==t&&o,p=L(this),c=void 0!==i&&"ios"===p,m="cycle"===s;return e(r,Object.assign({key:"2ddd1cf92efe244adb5a8086f8b7c537aa966684","no-router":!0,tabIndex:m&&o&&l?0:-1},a,{style:{zIndex:`${2e4+this.overlayIndex}`},class:Object.assign({[p]:!0,"modal-default":!c&&!o,"modal-card":c,"modal-sheet":o,"modal-no-expand-scroll":o&&!h,"overlay-hidden":!0,[M]:!1===d},$(this.cssClass)),onIonBackdropTap:this.onBackdropTap,onIonModalDidPresent:this.onLifecycle,onIonModalWillPresent:this.onLifecycle,onIonModalWillDismiss:this.onLifecycle,onIonModalDidDismiss:this.onLifecycle,onFocus:this.onModalFocus}),e("ion-backdrop",{key:"a757a70858d77aa13233e07d6a966b35a97ca41d",ref:t=>this.backdropEl=t,visible:this.showBackdrop,tappable:this.backdropDismiss,part:"backdrop"}),"ios"===p&&e("div",{key:"160d8c9d180924db0b0c51659c28b1eeaf28924a",class:"modal-shadow"}),e("div",Object.assign({key:"75ec5207aabb03a9e455a93da40a10ef1c24c771",role:"dialog"},n,{"aria-modal":"true",class:"modal-wrapper ion-overlay-wrapper",part:"content",ref:t=>this.wrapperEl=t}),l&&e("button",{key:"0a4fdf39c3086bcfcc72547b2fa45a8db20dca4f",class:"modal-handle",tabIndex:m?0:-1,"aria-label":"Activate to adjust the size of the dialog overlaying the screen",onClick:m?this.onHandleClick:void 0,part:"handle",ref:t=>this.dragHandleEl=t}),e("slot",{key:"ba6e90ee447db65f62ed659d4497d22463216823",onSlotchange:this.onSlotChange})))}get el(){return this}static get watchers(){return{isOpen:[{onIsOpenChange:0}],trigger:[{triggerChanged:0}]}}static get style(){return{ios:':host{--width:100%;--min-width:auto;--max-width:auto;--height:100%;--min-height:auto;--max-height:auto;--overflow:hidden;--border-radius:0;--border-width:0;--border-style:none;--border-color:transparent;--background:var(--ion-background-color, #fff);--box-shadow:none;--backdrop-opacity:0;left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:absolute;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;outline:none;color:var(--ion-text-color, #000);contain:strict}.modal-wrapper,ion-backdrop{pointer-events:auto}:host(.overlay-hidden){display:none}.modal-wrapper,.modal-shadow{border-radius:var(--border-radius);width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow);overflow:var(--overflow);z-index:10}.modal-shadow{position:absolute;background:transparent}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--width:600px;--height:500px;--ion-safe-area-top:0px;--ion-safe-area-bottom:0px;--ion-safe-area-right:0px;--ion-safe-area-left:0px}}@media only screen and (min-width: 768px) and (min-height: 768px){:host{--width:600px;--height:600px}}.modal-handle{left:0px;right:0px;top:5px;border-radius:8px;-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;position:absolute;width:36px;height:5px;-webkit-transform:translateZ(0);transform:translateZ(0);border:0;background:var(--ion-color-step-350, var(--ion-background-color-step-350, #c0c0be));cursor:pointer;z-index:11}.modal-handle::before{-webkit-padding-start:4px;padding-inline-start:4px;-webkit-padding-end:4px;padding-inline-end:4px;padding-top:4px;padding-bottom:4px;position:absolute;width:36px;height:5px;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);content:""}:host(.modal-sheet){--height:calc(100% - (var(--ion-safe-area-top) + 10px))}:host(.modal-sheet) .modal-wrapper,:host(.modal-sheet) .modal-shadow{position:absolute;bottom:0}:host(.modal-sheet.modal-no-expand-scroll) ion-footer{position:absolute;bottom:0;width:var(--width)}:host{--backdrop-opacity:var(--ion-backdrop-opacity, 0.4)}:host(.modal-card),:host(.modal-sheet){--border-radius:10px}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--border-radius:10px}}.modal-wrapper{-webkit-transform:translate3d(0, 100%, 0);transform:translate3d(0, 100%, 0)}@media screen and (max-width: 767px){@supports (width: max(0px, 1px)){:host(.modal-card){--height:calc(100% - max(30px, var(--ion-safe-area-top)) - 10px)}}@supports not (width: max(0px, 1px)){:host(.modal-card){--height:calc(100% - 40px)}}:host(.modal-card) .modal-wrapper{border-start-start-radius:var(--border-radius);border-start-end-radius:var(--border-radius);border-end-end-radius:0;border-end-start-radius:0}:host(.modal-card){--backdrop-opacity:0;--width:100%;-ms-flex-align:end;align-items:flex-end}:host(.modal-card) .modal-shadow{display:none}:host(.modal-card) ion-backdrop{pointer-events:none}}@media screen and (min-width: 768px){:host(.modal-card){--width:calc(100% - 120px);--height:calc(100% - (120px + var(--ion-safe-area-top) + var(--ion-safe-area-bottom)));--max-width:720px;--max-height:1000px;--backdrop-opacity:0;--box-shadow:0px 0px 30px 10px rgba(0, 0, 0, 0.1);-webkit-transition:all 0.5s ease-in-out;transition:all 0.5s ease-in-out}:host(.modal-card) .modal-wrapper{-webkit-box-shadow:none;box-shadow:none}:host(.modal-card) .modal-shadow{-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow)}}:host(.modal-sheet) .modal-wrapper{border-start-start-radius:var(--border-radius);border-start-end-radius:var(--border-radius);border-end-end-radius:0;border-end-start-radius:0}',md:':host{--width:100%;--min-width:auto;--max-width:auto;--height:100%;--min-height:auto;--max-height:auto;--overflow:hidden;--border-radius:0;--border-width:0;--border-style:none;--border-color:transparent;--background:var(--ion-background-color, #fff);--box-shadow:none;--backdrop-opacity:0;left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:absolute;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;outline:none;color:var(--ion-text-color, #000);contain:strict}.modal-wrapper,ion-backdrop{pointer-events:auto}:host(.overlay-hidden){display:none}.modal-wrapper,.modal-shadow{border-radius:var(--border-radius);width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow);overflow:var(--overflow);z-index:10}.modal-shadow{position:absolute;background:transparent}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--width:600px;--height:500px;--ion-safe-area-top:0px;--ion-safe-area-bottom:0px;--ion-safe-area-right:0px;--ion-safe-area-left:0px}}@media only screen and (min-width: 768px) and (min-height: 768px){:host{--width:600px;--height:600px}}.modal-handle{left:0px;right:0px;top:5px;border-radius:8px;-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;position:absolute;width:36px;height:5px;-webkit-transform:translateZ(0);transform:translateZ(0);border:0;background:var(--ion-color-step-350, var(--ion-background-color-step-350, #c0c0be));cursor:pointer;z-index:11}.modal-handle::before{-webkit-padding-start:4px;padding-inline-start:4px;-webkit-padding-end:4px;padding-inline-end:4px;padding-top:4px;padding-bottom:4px;position:absolute;width:36px;height:5px;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);content:""}:host(.modal-sheet){--height:calc(100% - (var(--ion-safe-area-top) + 10px))}:host(.modal-sheet) .modal-wrapper,:host(.modal-sheet) .modal-shadow{position:absolute;bottom:0}:host(.modal-sheet.modal-no-expand-scroll) ion-footer{position:absolute;bottom:0;width:var(--width)}:host{--backdrop-opacity:var(--ion-backdrop-opacity, 0.32)}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--border-radius:2px;--box-shadow:0 28px 48px rgba(0, 0, 0, 0.4)}}.modal-wrapper{-webkit-transform:translate3d(0, 40px, 0);transform:translate3d(0, 40px, 0);opacity:0.01}'}}},[289,"ion-modal",{hasController:[4,"has-controller"],overlayIndex:[2,"overlay-index"],delegate:[16],keyboardClose:[4,"keyboard-close"],enterAnimation:[16],leaveAnimation:[16],breakpoints:[16],expandToScroll:[4,"expand-to-scroll"],initialBreakpoint:[2,"initial-breakpoint"],backdropBreakpoint:[2,"backdrop-breakpoint"],handle:[4],handleBehavior:[1,"handle-behavior"],component:[1],componentProps:[16],cssClass:[1,"css-class"],backdropDismiss:[4,"backdrop-dismiss"],showBackdrop:[4,"show-backdrop"],animated:[4],presentingElement:[16],htmlAttributes:[16],isOpen:[4,"is-open"],trigger:[1],keepContentsMounted:[4,"keep-contents-mounted"],focusTrap:[4,"focus-trap"],canDismiss:[4,"can-dismiss"],isSheetModal:[32],presented:[32],present:[64],dismiss:[64],onDidDismiss:[64],onWillDismiss:[64],setCurrentBreakpoint:[64],getCurrentBreakpoint:[64]},[[9,"resize","onWindowResize"]],{isOpen:[{onIsOpenChange:0}],trigger:[{triggerChanged:0}]}]),dt={ionModalDidPresent:"ionViewDidEnter",ionModalWillPresent:"ionViewWillEnter",ionModalWillDismiss:"ionViewWillLeave",ionModalDidDismiss:"ionViewDidLeave"};function ht(){"undefined"!=typeof customElements&&["ion-modal","ion-backdrop"].forEach((t=>{switch(t){case"ion-modal":customElements.get(s(t))||customElements.define(s(t),nt);break;case"ion-backdrop":customElements.get(s(t))||F()}}))}export{nt as M,ht as d}