@ionic/core 9.0.0 → 9.0.1-dev.11787248963.10a00c73

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 (596) hide show
  1. package/components/index.js +1 -1
  2. package/components/ion-accordion-group.js +1 -1
  3. package/components/ion-accordion.js +1 -1
  4. package/components/ion-action-sheet.js +1 -1
  5. package/components/ion-alert.js +1 -1
  6. package/components/ion-app.js +1 -1
  7. package/components/ion-avatar.js +1 -1
  8. package/components/ion-back-button.js +1 -1
  9. package/components/ion-backdrop.js +1 -1
  10. package/components/ion-badge.js +1 -1
  11. package/components/ion-breadcrumb.js +1 -1
  12. package/components/ion-breadcrumbs.js +1 -1
  13. package/components/ion-button.js +1 -1
  14. package/components/ion-buttons.js +1 -1
  15. package/components/ion-card-content.js +1 -1
  16. package/components/ion-card-header.js +1 -1
  17. package/components/ion-card-subtitle.js +1 -1
  18. package/components/ion-card-title.js +1 -1
  19. package/components/ion-card.js +1 -1
  20. package/components/ion-checkbox.js +1 -1
  21. package/components/ion-chip.js +1 -1
  22. package/components/ion-col.js +1 -1
  23. package/components/ion-content.js +1 -1
  24. package/components/ion-datetime-button.js +1 -1
  25. package/components/ion-datetime.js +1 -1
  26. package/components/ion-fab-button.js +1 -1
  27. package/components/ion-fab-list.js +1 -1
  28. package/components/ion-fab.js +1 -1
  29. package/components/ion-footer.js +1 -1
  30. package/components/ion-grid.js +1 -1
  31. package/components/ion-header.js +1 -1
  32. package/components/ion-icon.js +1 -1
  33. package/components/ion-img.js +1 -1
  34. package/components/ion-infinite-scroll-content.js +1 -1
  35. package/components/ion-infinite-scroll.js +1 -1
  36. package/components/ion-input-otp.js +1 -1
  37. package/components/ion-input-password-toggle.js +1 -1
  38. package/components/ion-input.js +1 -1
  39. package/components/ion-item-divider.js +1 -1
  40. package/components/ion-item-group.js +1 -1
  41. package/components/ion-item-option.js +1 -1
  42. package/components/ion-item-options.js +1 -1
  43. package/components/ion-item-sliding.js +1 -1
  44. package/components/ion-item.js +1 -1
  45. package/components/ion-label.js +1 -1
  46. package/components/ion-list-header.js +1 -1
  47. package/components/ion-list.js +1 -1
  48. package/components/ion-loading.js +1 -1
  49. package/components/ion-menu-button.js +1 -1
  50. package/components/ion-menu-toggle.js +1 -1
  51. package/components/ion-menu.js +1 -1
  52. package/components/ion-modal.js +1 -1
  53. package/components/ion-nav-link.js +1 -1
  54. package/components/ion-nav.js +1 -1
  55. package/components/ion-note.js +1 -1
  56. package/components/ion-picker-column-option.js +1 -1
  57. package/components/ion-picker-column.js +1 -1
  58. package/components/ion-picker.js +1 -1
  59. package/components/ion-popover.js +1 -1
  60. package/components/ion-progress-bar.js +1 -1
  61. package/components/ion-radio-group.js +1 -1
  62. package/components/ion-radio.js +1 -1
  63. package/components/ion-range.js +1 -1
  64. package/components/ion-refresher-content.js +1 -1
  65. package/components/ion-refresher.js +1 -1
  66. package/components/ion-reorder-group.js +1 -1
  67. package/components/ion-reorder.js +1 -1
  68. package/components/ion-ripple-effect.js +1 -1
  69. package/components/ion-route-redirect.js +1 -1
  70. package/components/ion-route.js +1 -1
  71. package/components/ion-router-link.js +1 -1
  72. package/components/ion-router-outlet.js +1 -1
  73. package/components/ion-router.js +1 -1
  74. package/components/ion-row.js +1 -1
  75. package/components/ion-searchbar.js +1 -1
  76. package/components/ion-segment-button.js +1 -1
  77. package/components/ion-segment-content.js +1 -1
  78. package/components/ion-segment-view.js +1 -1
  79. package/components/ion-segment.js +1 -1
  80. package/components/ion-select-modal.js +1 -1
  81. package/components/ion-select-option.js +1 -1
  82. package/components/ion-select-popover.js +1 -1
  83. package/components/ion-select.js +1 -1
  84. package/components/ion-skeleton-text.js +1 -1
  85. package/components/ion-spinner.js +1 -1
  86. package/components/ion-split-pane.js +1 -1
  87. package/components/ion-tab-bar.js +1 -1
  88. package/components/ion-tab-button.js +1 -1
  89. package/components/ion-tab.js +1 -1
  90. package/components/ion-tabs.js +1 -1
  91. package/components/ion-text.js +1 -1
  92. package/components/ion-textarea.js +1 -1
  93. package/components/ion-thumbnail.js +1 -1
  94. package/components/ion-title.js +1 -1
  95. package/components/ion-toast.js +1 -1
  96. package/components/ion-toggle.js +1 -1
  97. package/components/ion-toolbar.js +1 -1
  98. package/components/{p-63OhffQv.js → p-66ogmUZU.js} +1 -1
  99. package/components/p-6Vp915Y7.js +4 -0
  100. package/components/p-7PNwKFZi.js +4 -0
  101. package/components/{p-G0TxqHfe.js → p-A8MJRBIY.js} +1 -1
  102. package/components/p-AQcCdH2_.js +4 -0
  103. package/{dist/ionic/p-Dn0mqQ_R.js → components/p-B6x5_b9w.js} +1 -1
  104. package/components/p-B8MQjdvk.js +4 -0
  105. package/components/p-BA_4ZIEg.js +4 -0
  106. package/components/p-BFtL8t1r.js +4 -0
  107. package/components/{p-DaA_8eqt.js → p-BMfgF-Tv.js} +1 -1
  108. package/components/p-BPDxVIRr.js +4 -0
  109. package/components/p-BSARlp49.js +4 -0
  110. package/components/p-B_gJaBk0.js +4 -0
  111. package/components/p-BdwCtX8Y.js +4 -0
  112. package/components/p-Bg4OwDwb.js +4 -0
  113. package/components/{p-DV85C0e0.js → p-BgUIV8NQ.js} +1 -1
  114. package/components/p-Bnc0m4SW.js +4 -0
  115. package/components/p-BpLt_Ptn.js +4 -0
  116. package/components/p-BqBDq1Ma.js +4 -0
  117. package/components/{p-C_phlPMC.js → p-BrFaQbGY.js} +1 -1
  118. package/{dist/ionic/p-Cdjxf_yg.js → components/p-BuPAFTWI.js} +1 -1
  119. package/components/p-Bx2saTHs.js +4 -0
  120. package/components/p-BxhE2W85.js +4 -0
  121. package/components/p-CHswSpKy.js +4 -0
  122. package/components/{p-fruGqVHh.js → p-CQAjyETU.js} +1 -1
  123. package/components/{p-1jI5oW-W.js → p-CR9OgE6N.js} +1 -1
  124. package/components/p-CWETxTjE.js +4 -0
  125. package/components/p-CaZeZIL2.js +4 -0
  126. package/components/p-CaiZOhfC.js +4 -0
  127. package/components/p-CgvDC7hC.js +4 -0
  128. package/components/{p-BqPNzJf6.js → p-CqyGR9Aq.js} +1 -1
  129. package/components/{p-UIBJkZf8.js → p-D0YpjgON.js} +1 -1
  130. package/components/p-D7ysFE2B.js +4 -0
  131. package/{dist/ionic/p-4eOQC00Z.js → components/p-DCWfzDM8.js} +1 -1
  132. package/components/{p-DwpKZ6rl.js → p-DDdkefwf.js} +1 -1
  133. package/components/{p-DzRT60Tw.js → p-DEW7CnUc.js} +1 -1
  134. package/components/p-DQ1IPvZO.js +4 -0
  135. package/components/p-DcOH6-o5.js +4 -0
  136. package/components/{p-DD5fQ4EQ.js → p-DfdYCsov.js} +1 -1
  137. package/components/{p-DSzSbVP2.js → p-DhOoEIAs.js} +1 -1
  138. package/components/{p-DM-PrAoh.js → p-Dl_7b_UJ.js} +1 -1
  139. package/components/p-DqAI6tg7.js +4 -0
  140. package/components/p-DrehWDfv.js +4 -0
  141. package/components/{p-ryyf_ItD.js → p-DysqCsJu.js} +1 -1
  142. package/components/p-H1f2qsk4.js +4 -0
  143. package/components/p-HVYBAhFx.js +4 -0
  144. package/components/{p-CbhUdtjf.js → p-Kmrg3Fed.js} +1 -1
  145. package/components/{p-Bjig0DJK.js → p-RFfE9hF6.js} +1 -1
  146. package/{dist/ionic/p-CBWAXjA5.js → components/p-SR-LLqp_.js} +1 -1
  147. package/components/p-eFI3mtEX.js +4 -0
  148. package/components/p-gFwXiYC_.js +4 -0
  149. package/components/p-tX3UxCnU.js +4 -0
  150. package/components/p-v2NpoOHp.js +4 -0
  151. package/dist/cjs/{animation-C0mOHzej.js → animation-D-OqR4a4.js} +1 -1
  152. package/dist/cjs/{app-globals-BREG4twP.js → app-globals-BzgwARwJ.js} +1 -1
  153. package/dist/cjs/{button-active-CVMevT9a.js → button-active-BlWSD7uK.js} +2 -2
  154. package/dist/cjs/{format-pp0Du3K-.js → format-D7ig6Vm0.js} +1 -1
  155. package/dist/cjs/{framework-delegate-Dfo5XsGv.js → framework-delegate-BZUx4TnE.js} +1 -1
  156. package/dist/cjs/{gesture-controller-BDUH7687.js → gesture-controller-CeJslptU.js} +6 -14
  157. package/dist/cjs/{hardware-back-button-fqpYh-kd.js → hardware-back-button-JOAEFSzc.js} +1 -1
  158. package/dist/cjs/{helpers-YPQybDph.js → helpers-Dj5o76mq.js} +1 -1
  159. package/dist/cjs/{index-BLdJCcJY.js → index-2sO-zkZ2.js} +4 -4
  160. package/dist/cjs/{index-uvry__L4.js → index-BrVMoqUk.js} +3 -1
  161. package/dist/cjs/{index-zVCah4Uz.js → index-C8zH6b3d.js} +2 -2
  162. package/dist/cjs/{index-DXsPSne6.js → index-CZ6vzt_q.js} +5 -5
  163. package/dist/cjs/{index-DDg31ZF5.js → index-Csue6G3m.js} +2 -2
  164. package/dist/cjs/{index-DwlRtFZe.js → index-DRPqwSvU.js} +1 -1
  165. package/dist/cjs/{index-B7zJsYWS.js → index-EJLjthTK.js} +1 -2
  166. package/dist/cjs/index.cjs.js +14 -14
  167. package/dist/cjs/{input-shims-Cbu1fcye.js → input-shims-Bh7bnt2v.js} +3 -3
  168. package/dist/cjs/{input.utils-BZdMWVrt.js → input.utils-Cq3g9uHy.js} +1 -1
  169. package/dist/cjs/ion-accordion_2.cjs.entry.js +335 -364
  170. package/dist/cjs/ion-action-sheet.cjs.entry.js +60 -140
  171. package/dist/cjs/ion-alert.cjs.entry.js +67 -159
  172. package/dist/cjs/ion-app_8.cjs.entry.js +163 -258
  173. package/dist/cjs/ion-avatar_3.cjs.entry.js +2 -8
  174. package/dist/cjs/ion-back-button.cjs.entry.js +21 -45
  175. package/dist/cjs/ion-backdrop.cjs.entry.js +14 -18
  176. package/dist/cjs/ion-breadcrumb_2.cjs.entry.js +117 -195
  177. package/dist/cjs/ion-button_2.cjs.entry.js +61 -130
  178. package/dist/cjs/ion-card_5.cjs.entry.js +28 -80
  179. package/dist/cjs/ion-checkbox.cjs.entry.js +98 -147
  180. package/dist/cjs/ion-chip.cjs.entry.js +10 -16
  181. package/dist/cjs/ion-col_3.cjs.entry.js +6 -126
  182. package/dist/cjs/ion-datetime-button.cjs.entry.js +232 -248
  183. package/dist/cjs/ion-datetime.cjs.entry.js +775 -953
  184. package/dist/cjs/ion-fab_3.cjs.entry.js +78 -136
  185. package/dist/cjs/ion-img.cjs.entry.js +11 -31
  186. package/dist/cjs/ion-infinite-scroll_2.cjs.entry.js +71 -98
  187. package/dist/cjs/ion-input-otp.cjs.entry.js +352 -424
  188. package/dist/cjs/ion-input-password-toggle.cjs.entry.js +14 -29
  189. package/dist/cjs/ion-input.cjs.entry.js +158 -302
  190. package/dist/cjs/ion-item-option_3.cjs.entry.js +54 -98
  191. package/dist/cjs/ion-item_8.cjs.entry.js +61 -157
  192. package/dist/cjs/ion-loading.cjs.entry.js +54 -131
  193. package/dist/cjs/ion-menu_3.cjs.entry.js +94 -158
  194. package/dist/cjs/ion-modal.cjs.entry.js +206 -362
  195. package/dist/cjs/ion-nav_2.cjs.entry.js +26 -78
  196. package/dist/cjs/ion-picker-column-option.cjs.entry.js +23 -33
  197. package/dist/cjs/ion-picker-column.cjs.entry.js +389 -410
  198. package/dist/cjs/ion-picker.cjs.entry.js +390 -400
  199. package/dist/cjs/ion-popover.cjs.entry.js +184 -292
  200. package/dist/cjs/ion-progress-bar.cjs.entry.js +23 -29
  201. package/dist/cjs/ion-radio_2.cjs.entry.js +128 -201
  202. package/dist/cjs/ion-range.cjs.entry.js +223 -293
  203. package/dist/cjs/ion-refresher_2.cjs.entry.js +89 -154
  204. package/dist/cjs/ion-reorder_2.cjs.entry.js +19 -49
  205. package/dist/cjs/ion-ripple-effect.cjs.entry.js +13 -13
  206. package/dist/cjs/ion-route_4.cjs.entry.js +45 -144
  207. package/dist/cjs/ion-searchbar.cjs.entry.js +182 -268
  208. package/dist/cjs/ion-segment-content.cjs.entry.js +1 -1
  209. package/dist/cjs/ion-segment-view.cjs.entry.js +12 -24
  210. package/dist/cjs/ion-segment_2.cjs.entry.js +122 -161
  211. package/dist/cjs/ion-select-modal.cjs.entry.js +19 -21
  212. package/dist/cjs/ion-select_3.cjs.entry.js +151 -319
  213. package/dist/cjs/ion-spinner.cjs.entry.js +6 -21
  214. package/dist/cjs/ion-split-pane.cjs.entry.js +14 -27
  215. package/dist/cjs/ion-tab-bar_2.cjs.entry.js +32 -89
  216. package/dist/cjs/ion-tab_2.cjs.entry.js +22 -49
  217. package/dist/cjs/ion-text.cjs.entry.js +2 -8
  218. package/dist/cjs/ion-textarea.cjs.entry.js +139 -256
  219. package/dist/cjs/ion-toast.cjs.entry.js +106 -221
  220. package/dist/cjs/ion-toggle.cjs.entry.js +114 -165
  221. package/dist/cjs/{ionic-global-k6hOWWpn.js → ionic-global-DvgIzM2F.js} +1 -1
  222. package/dist/cjs/ionic.cjs.js +4 -4
  223. package/dist/cjs/{ios.transition-zTmJz8T-.js → ios.transition-zIgdoSYe.js} +4 -4
  224. package/dist/cjs/{item-multiple-inputs-BdYSbfKN.js → item-multiple-inputs-DG-ZGm6j.js} +1 -1
  225. package/dist/cjs/loader.cjs.js +4 -4
  226. package/dist/cjs/{md.transition-nb_4pUXu.js → md.transition-CXeJ9rfh.js} +4 -4
  227. package/dist/cjs/{overlays-KaNVDNqC.js → overlays-Bg0auTQa.js} +6 -6
  228. package/dist/cjs/{select-option-render-pULCGldr.js → select-option-render-7m1WdFzF.js} +2 -2
  229. package/dist/cjs/{slot-mutation-controller-DPHmqXdV.js → slot-mutation-controller-BJEJzx_e.js} +1 -1
  230. package/dist/cjs/{status-tap-o9IIymsP.js → status-tap-DxbUM5XX.js} +3 -3
  231. package/dist/cjs/{swipe-back-B7X9VOlH.js → swipe-back-F_DBt-Aw.js} +4 -4
  232. package/dist/collection/components/accordion/accordion.js +310 -314
  233. package/dist/collection/components/accordion-group/accordion-group.js +23 -46
  234. package/dist/collection/components/action-sheet/action-sheet.js +49 -128
  235. package/dist/collection/components/action-sheet/test/basic/fixture.js +0 -3
  236. package/dist/collection/components/alert/alert.js +56 -147
  237. package/dist/collection/components/app/app.js +0 -3
  238. package/dist/collection/components/back-button/back-button.js +19 -42
  239. package/dist/collection/components/backdrop/backdrop.js +14 -16
  240. package/dist/collection/components/badge/badge.js +0 -6
  241. package/dist/collection/components/breadcrumb/breadcrumb.js +29 -90
  242. package/dist/collection/components/breadcrumbs/breadcrumbs.js +87 -102
  243. package/dist/collection/components/button/button.js +59 -127
  244. package/dist/collection/components/buttons/buttons.js +15 -13
  245. package/dist/collection/components/card/card.js +20 -53
  246. package/dist/collection/components/card-header/card-header.js +8 -12
  247. package/dist/collection/components/card-subtitle/card-subtitle.js +0 -6
  248. package/dist/collection/components/card-title/card-title.js +0 -6
  249. package/dist/collection/components/checkbox/checkbox.js +95 -143
  250. package/dist/collection/components/chip/chip.js +10 -14
  251. package/dist/collection/components/col/col.js +0 -120
  252. package/dist/collection/components/content/content.js +60 -90
  253. package/dist/collection/components/datetime/datetime.js +762 -939
  254. package/dist/collection/components/datetime-button/datetime-button.js +229 -244
  255. package/dist/collection/components/fab/fab.js +13 -20
  256. package/dist/collection/components/fab-button/fab-button.js +54 -103
  257. package/dist/collection/components/fab-list/fab-list.js +11 -10
  258. package/dist/collection/components/footer/footer.js +43 -49
  259. package/dist/collection/components/grid/grid.js +6 -4
  260. package/dist/collection/components/header/header.js +23 -33
  261. package/dist/collection/components/img/img.js +9 -28
  262. package/dist/collection/components/infinite-scroll/infinite-scroll.js +66 -73
  263. package/dist/collection/components/infinite-scroll-content/infinite-scroll-content.js +3 -20
  264. package/dist/collection/components/input/input.js +154 -297
  265. package/dist/collection/components/input-otp/input-otp.js +350 -421
  266. package/dist/collection/components/input-password-toggle/input-password-toggle.js +13 -27
  267. package/dist/collection/components/item/item.js +37 -80
  268. package/dist/collection/components/item-divider/item-divider.js +10 -15
  269. package/dist/collection/components/item-option/item-option.js +20 -48
  270. package/dist/collection/components/item-options/item-options.js +7 -10
  271. package/dist/collection/components/item-sliding/item-sliding.js +26 -36
  272. package/dist/collection/components/label/label.js +4 -24
  273. package/dist/collection/components/list/list.js +6 -9
  274. package/dist/collection/components/list-header/list-header.js +0 -10
  275. package/dist/collection/components/loading/loading.js +46 -122
  276. package/dist/collection/components/menu/menu.js +55 -99
  277. package/dist/collection/components/menu-button/menu-button.js +19 -28
  278. package/dist/collection/components/menu-toggle/menu-toggle.js +13 -20
  279. package/dist/collection/components/modal/modal.js +196 -351
  280. package/dist/collection/components/modal/test/fixtures.js +0 -3
  281. package/dist/collection/components/nav/nav.js +12 -45
  282. package/dist/collection/components/nav/view-controller.js +1 -7
  283. package/dist/collection/components/nav-link/nav-link.js +9 -20
  284. package/dist/collection/components/note/note.js +0 -6
  285. package/dist/collection/components/picker/picker.js +388 -397
  286. package/dist/collection/components/picker-column/picker-column.js +389 -409
  287. package/dist/collection/components/picker-column-option/picker-column-option.js +21 -30
  288. package/dist/collection/components/popover/popover.js +176 -283
  289. package/dist/collection/components/popover/test/fixture.js +0 -1
  290. package/dist/collection/components/progress-bar/progress-bar.js +22 -26
  291. package/dist/collection/components/radio/radio.js +62 -98
  292. package/dist/collection/components/radio-group/radio-group.js +64 -99
  293. package/dist/collection/components/radio-group/test/fixtures.js +0 -2
  294. package/dist/collection/components/range/range.js +220 -289
  295. package/dist/collection/components/refresher/refresher.js +79 -105
  296. package/dist/collection/components/refresher-content/refresher-content.js +3 -40
  297. package/dist/collection/components/reorder/reorder.js +0 -1
  298. package/dist/collection/components/reorder-group/reorder-group.js +14 -43
  299. package/dist/collection/components/ripple-effect/ripple-effect.js +12 -11
  300. package/dist/collection/components/route/route.js +9 -38
  301. package/dist/collection/components/route-redirect/route-redirect.js +0 -31
  302. package/dist/collection/components/router/router.js +27 -35
  303. package/dist/collection/components/router/utils/matching.js +0 -1
  304. package/dist/collection/components/router-link/router-link.js +10 -35
  305. package/dist/collection/components/router-outlet/router-outlet.js +12 -34
  306. package/dist/collection/components/searchbar/searchbar.js +180 -265
  307. package/dist/collection/components/segment/segment.js +76 -113
  308. package/dist/collection/components/segment-button/segment-button.js +44 -44
  309. package/dist/collection/components/segment-view/segment-view.js +12 -23
  310. package/dist/collection/components/select/select.js +127 -240
  311. package/dist/collection/components/select-modal/select-modal.js +11 -12
  312. package/dist/collection/components/select-modal/test/fixtures.js +1 -8
  313. package/dist/collection/components/select-option/select-option.js +7 -44
  314. package/dist/collection/components/select-popover/select-popover.js +10 -25
  315. package/dist/collection/components/select-popover/test/fixtures.js +1 -8
  316. package/dist/collection/components/skeleton-text/skeleton-text.js +6 -10
  317. package/dist/collection/components/spinner/spinner.js +6 -19
  318. package/dist/collection/components/split-pane/split-pane.js +13 -25
  319. package/dist/collection/components/tab/tab.js +4 -15
  320. package/dist/collection/components/tab-bar/tab-bar.js +12 -30
  321. package/dist/collection/components/tab-button/tab-button.js +19 -56
  322. package/dist/collection/components/tabs/tabs.js +17 -31
  323. package/dist/collection/components/text/text.js +0 -6
  324. package/dist/collection/components/textarea/textarea.js +135 -251
  325. package/dist/collection/components/title/title.js +0 -16
  326. package/dist/collection/components/toast/toast.js +97 -211
  327. package/dist/collection/components/toggle/toggle.js +111 -161
  328. package/dist/collection/components/toolbar/toolbar.js +3 -8
  329. package/dist/collection/global/config.js +3 -1
  330. package/dist/collection/utils/gesture/gesture-controller.js +6 -14
  331. package/dist/collection/utils/sanitization/index.js +0 -1
  332. package/dist/collection/utils/test/late-props/late-props.js +69 -0
  333. package/dist/collection/utils/test/playwright/page/event-spy.js +8 -9
  334. package/dist/collection/utils/test/press-keys.js +1 -4
  335. package/dist/docs.json +1 -1
  336. package/dist/esm/{animation-CGFdmGk9.js → animation-TxGPYeDn.js} +1 -1
  337. package/dist/esm/{app-globals-CYmMeGdU.js → app-globals-Do8rJest.js} +1 -1
  338. package/dist/esm/{button-active-BDOsVAiZ.js → button-active-ChA4D-ml.js} +2 -2
  339. package/dist/esm/{format-Dcwga61t.js → format-CVk5e_GP.js} +2 -2
  340. package/dist/esm/{framework-delegate-BHTU2Ip9.js → framework-delegate-DaLWnISz.js} +1 -1
  341. package/dist/esm/{gesture-controller-TXPDHL13.js → gesture-controller-B_gJaBk0.js} +6 -14
  342. package/dist/esm/{hardware-back-button-gLJHMX_F.js → hardware-back-button-D8W4L0JP.js} +1 -1
  343. package/dist/esm/{helpers-CAGf8Wgp.js → helpers-BIgoInJU.js} +1 -1
  344. package/dist/esm/{index-DcPaH5uL.js → index-BmLuEdV7.js} +1 -1
  345. package/dist/esm/{index-T0JxBI8V.js → index-BmOR8tCv.js} +2 -2
  346. package/dist/esm/{index-CqneaaGd.js → index-C5ZdL0qp.js} +5 -5
  347. package/dist/esm/{index-WlteAIqz.js → index-C8Dsa6li.js} +4 -4
  348. package/dist/esm/{index-ChhhtsGZ.js → index-CKYcsw8f.js} +3 -1
  349. package/dist/esm/{index-Clc-28O1.js → index-DHw2lZxe.js} +2 -2
  350. package/dist/esm/{index-CKM1DdGm.js → index-elneMH8y.js} +1 -2
  351. package/dist/esm/index.js +14 -14
  352. package/dist/esm/{input-shims-B8sfni1e.js → input-shims-09NN97kF.js} +3 -3
  353. package/dist/esm/{input.utils-B1ValN_N.js → input.utils-BxyH9l1w.js} +1 -1
  354. package/dist/esm/ion-accordion_2.entry.js +335 -364
  355. package/dist/esm/ion-action-sheet.entry.js +60 -140
  356. package/dist/esm/ion-alert.entry.js +67 -159
  357. package/dist/esm/ion-app_8.entry.js +163 -258
  358. package/dist/esm/ion-avatar_3.entry.js +2 -8
  359. package/dist/esm/ion-back-button.entry.js +21 -45
  360. package/dist/esm/ion-backdrop.entry.js +14 -18
  361. package/dist/esm/ion-breadcrumb_2.entry.js +117 -195
  362. package/dist/esm/ion-button_2.entry.js +61 -130
  363. package/dist/esm/ion-card_5.entry.js +28 -80
  364. package/dist/esm/ion-checkbox.entry.js +98 -147
  365. package/dist/esm/ion-chip.entry.js +10 -16
  366. package/dist/esm/ion-col_3.entry.js +6 -126
  367. package/dist/esm/ion-datetime-button.entry.js +232 -248
  368. package/dist/esm/ion-datetime.entry.js +775 -953
  369. package/dist/esm/ion-fab_3.entry.js +78 -136
  370. package/dist/esm/ion-img.entry.js +11 -31
  371. package/dist/esm/ion-infinite-scroll_2.entry.js +71 -98
  372. package/dist/esm/ion-input-otp.entry.js +352 -424
  373. package/dist/esm/ion-input-password-toggle.entry.js +14 -29
  374. package/dist/esm/ion-input.entry.js +158 -302
  375. package/dist/esm/ion-item-option_3.entry.js +54 -98
  376. package/dist/esm/ion-item_8.entry.js +61 -157
  377. package/dist/esm/ion-loading.entry.js +54 -131
  378. package/dist/esm/ion-menu_3.entry.js +94 -158
  379. package/dist/esm/ion-modal.entry.js +206 -362
  380. package/dist/esm/ion-nav_2.entry.js +26 -78
  381. package/dist/esm/ion-picker-column-option.entry.js +23 -33
  382. package/dist/esm/ion-picker-column.entry.js +389 -410
  383. package/dist/esm/ion-picker.entry.js +390 -400
  384. package/dist/esm/ion-popover.entry.js +184 -292
  385. package/dist/esm/ion-progress-bar.entry.js +23 -29
  386. package/dist/esm/ion-radio_2.entry.js +128 -201
  387. package/dist/esm/ion-range.entry.js +223 -293
  388. package/dist/esm/ion-refresher_2.entry.js +89 -154
  389. package/dist/esm/ion-reorder_2.entry.js +19 -49
  390. package/dist/esm/ion-ripple-effect.entry.js +13 -13
  391. package/dist/esm/ion-route_4.entry.js +45 -144
  392. package/dist/esm/ion-searchbar.entry.js +182 -268
  393. package/dist/esm/ion-segment-content.entry.js +1 -1
  394. package/dist/esm/ion-segment-view.entry.js +12 -24
  395. package/dist/esm/ion-segment_2.entry.js +122 -161
  396. package/dist/esm/ion-select-modal.entry.js +19 -21
  397. package/dist/esm/ion-select_3.entry.js +151 -319
  398. package/dist/esm/ion-spinner.entry.js +6 -21
  399. package/dist/esm/ion-split-pane.entry.js +14 -27
  400. package/dist/esm/ion-tab-bar_2.entry.js +32 -89
  401. package/dist/esm/ion-tab_2.entry.js +22 -49
  402. package/dist/esm/ion-text.entry.js +2 -8
  403. package/dist/esm/ion-textarea.entry.js +139 -256
  404. package/dist/esm/ion-toast.entry.js +106 -221
  405. package/dist/esm/ion-toggle.entry.js +114 -165
  406. package/dist/esm/{ionic-global-BVB7BrLT.js → ionic-global-lrowsHfi.js} +1 -1
  407. package/dist/esm/ionic.js +5 -5
  408. package/dist/esm/{ios.transition-DXRCmcbC.js → ios.transition-BQhADrk1.js} +4 -4
  409. package/dist/esm/{item-multiple-inputs-rU8VaNNg.js → item-multiple-inputs-D_N3fDkD.js} +1 -1
  410. package/dist/esm/loader.js +5 -5
  411. package/dist/esm/{md.transition-BMngO4i_.js → md.transition-D58NpmRa.js} +4 -4
  412. package/dist/esm/{overlays-CPmIs9Ls.js → overlays-BpnIFlXI.js} +6 -6
  413. package/dist/esm/{select-option-render-C4m76VGH.js → select-option-render-lIuu64EV.js} +2 -2
  414. package/dist/esm/{slot-mutation-controller-DiE_C9un.js → slot-mutation-controller-rS_T3FDR.js} +1 -1
  415. package/dist/esm/{status-tap-CHB7KwIb.js → status-tap-CpFQMLl6.js} +3 -3
  416. package/dist/esm/{swipe-back-C9HW1bug.js → swipe-back-rmc7zeNW.js} +4 -4
  417. package/dist/ionic/index.esm.js +1 -1
  418. package/dist/ionic/ionic.esm.js +1 -1
  419. package/dist/ionic/p-05800a02.entry.js +4 -0
  420. package/dist/ionic/p-0eb50dca.entry.js +4 -0
  421. package/dist/ionic/p-16e9f542.entry.js +4 -0
  422. package/dist/ionic/p-18d532a3.entry.js +4 -0
  423. package/dist/ionic/p-1db2afb4.entry.js +4 -0
  424. package/dist/ionic/p-1df75f9e.entry.js +4 -0
  425. package/dist/ionic/p-295ff427.entry.js +4 -0
  426. package/dist/ionic/p-34b9379b.entry.js +4 -0
  427. package/dist/ionic/p-39a8d4e0.entry.js +4 -0
  428. package/dist/ionic/p-4437015c.entry.js +4 -0
  429. package/dist/ionic/p-478035a7.entry.js +4 -0
  430. package/dist/ionic/p-485fb218.entry.js +4 -0
  431. package/dist/ionic/p-48c859fe.entry.js +4 -0
  432. package/dist/ionic/p-49b9d405.entry.js +4 -0
  433. package/dist/ionic/p-56307aea.entry.js +4 -0
  434. package/dist/ionic/p-5b906fd6.entry.js +4 -0
  435. package/dist/ionic/p-5ee2d7b1.entry.js +4 -0
  436. package/dist/ionic/p-5f216b79.entry.js +4 -0
  437. package/dist/ionic/p-61c799d1.entry.js +4 -0
  438. package/dist/ionic/p-63bbba8d.entry.js +4 -0
  439. package/dist/ionic/p-68507e70.entry.js +4 -0
  440. package/dist/ionic/{p-ded69ceb.entry.js → p-6f048604.entry.js} +1 -1
  441. package/dist/ionic/p-70ee8888.entry.js +4 -0
  442. package/dist/ionic/p-72ad7c64.entry.js +4 -0
  443. package/dist/ionic/p-75887ee0.entry.js +4 -0
  444. package/dist/ionic/p-873a315a.entry.js +4 -0
  445. package/dist/ionic/p-881b6954.entry.js +4 -0
  446. package/dist/ionic/p-886d9e66.entry.js +4 -0
  447. package/dist/ionic/p-8dd4c026.entry.js +4 -0
  448. package/dist/ionic/p-8e007f11.entry.js +4 -0
  449. package/dist/ionic/p-8f51110d.entry.js +4 -0
  450. package/dist/ionic/p-90ba736e.entry.js +4 -0
  451. package/dist/ionic/p-959df5f8.entry.js +4 -0
  452. package/dist/ionic/p-9e455875.entry.js +4 -0
  453. package/dist/ionic/{p-CBR_W98Z.js → p-9wczfs_v.js} +1 -1
  454. package/dist/ionic/p-B1Y7LZhV.js +4 -0
  455. package/dist/ionic/p-B5RyLYvl.js +4 -0
  456. package/dist/ionic/{p-CPcPmkGv.js → p-BQv5i5Kf.js} +1 -1
  457. package/{components/p-8FN7p701.js → dist/ionic/p-BZVE25Gu.js} +1 -1
  458. package/{components/p-DFvZn99E.js → dist/ionic/p-BZxjcGRP.js} +1 -1
  459. package/dist/ionic/p-B_gJaBk0.js +4 -0
  460. package/dist/ionic/p-BnGA34Pd.js +4 -0
  461. package/dist/ionic/p-ByLaqOPm.js +4 -0
  462. package/dist/ionic/p-C06QNN45.js +4 -0
  463. package/dist/ionic/p-C4IBDDj6.js +4 -0
  464. package/dist/ionic/p-CCVlNZ__.js +4 -0
  465. package/dist/ionic/{p-CMRtMbJc.js → p-CDBop-kz.js} +1 -1
  466. package/dist/ionic/p-CKYcsw8f.js +5 -0
  467. package/dist/ionic/p-CazSodad.js +4 -0
  468. package/{components/p-ia3IDdJS.js → dist/ionic/p-ClrlQU2y.js} +1 -1
  469. package/dist/ionic/{p-UIBJkZf8.js → p-D0YpjgON.js} +1 -1
  470. package/dist/ionic/p-D0dfUysx.js +4 -0
  471. package/dist/ionic/{p-BB0LlG4y.js → p-D9yvytgv.js} +1 -1
  472. package/{components/p-C5KYjZWD.js → dist/ionic/p-DF_Uqql8.js} +1 -1
  473. package/dist/ionic/{p-BYEAtHr-.js → p-DXJgZWgi.js} +1 -1
  474. package/dist/ionic/{p-D94_RztK.js → p-DdhHqKj-.js} +1 -1
  475. package/dist/ionic/p-De0eY881.js +4 -0
  476. package/dist/ionic/p-DgUL3JbO.js +4 -0
  477. package/dist/ionic/{p-7CBuOvEo.js → p-RzUn7cKs.js} +1 -1
  478. package/dist/ionic/p-VquyMbjp.js +4 -0
  479. package/dist/ionic/p-a0fee899.entry.js +4 -0
  480. package/dist/ionic/p-a54bcd16.entry.js +4 -0
  481. package/dist/ionic/p-aebc4d69.entry.js +4 -0
  482. package/dist/ionic/p-b5f37106.entry.js +4 -0
  483. package/dist/ionic/{p-40424a88.entry.js → p-b62bfce8.entry.js} +1 -1
  484. package/dist/ionic/p-b7a11b58.entry.js +4 -0
  485. package/dist/ionic/p-bbf6878c.entry.js +4 -0
  486. package/dist/ionic/p-c49165af.entry.js +4 -0
  487. package/dist/ionic/p-cad4eccf.entry.js +4 -0
  488. package/dist/ionic/p-cdc5115e.entry.js +4 -0
  489. package/dist/ionic/p-d3384a40.entry.js +4 -0
  490. package/dist/ionic/p-d8bae128.entry.js +4 -0
  491. package/dist/ionic/p-d8deff43.entry.js +4 -0
  492. package/dist/ionic/p-ddfb7e5f.entry.js +4 -0
  493. package/dist/ionic/p-e538f18d.entry.js +4 -0
  494. package/dist/ionic/p-f376876b.entry.js +4 -0
  495. package/dist/ionic/p-f7dd1ed9.entry.js +4 -0
  496. package/dist/ionic/p-fbd83d4c.entry.js +4 -0
  497. package/dist/types/components/refresher/refresher.d.ts +7 -0
  498. package/hydrate/index.js +5450 -8380
  499. package/hydrate/index.mjs +5450 -8380
  500. package/package.json +1 -1
  501. package/components/p--m5cCjbK.js +0 -4
  502. package/components/p-B4uHHhPK.js +0 -4
  503. package/components/p-BNJOu1Q2.js +0 -4
  504. package/components/p-BOvLNVKq.js +0 -4
  505. package/components/p-BeamQXHF.js +0 -4
  506. package/components/p-BjluhQMI.js +0 -4
  507. package/components/p-BlsIikdZ.js +0 -4
  508. package/components/p-BrD9Xv62.js +0 -4
  509. package/components/p-BvJqoZ5R.js +0 -4
  510. package/components/p-Bz6z3Asd.js +0 -4
  511. package/components/p-C6HnVvHO.js +0 -4
  512. package/components/p-C7jvh5Wy.js +0 -4
  513. package/components/p-C9BGR5fy.js +0 -4
  514. package/components/p-CB-y1CdP.js +0 -4
  515. package/components/p-CHH3loEE.js +0 -4
  516. package/components/p-CJKUWjmg.js +0 -4
  517. package/components/p-CMLAwl_N.js +0 -4
  518. package/components/p-CejmQs3h.js +0 -4
  519. package/components/p-CtZqa4HM.js +0 -4
  520. package/components/p-D9qIVSWm.js +0 -4
  521. package/components/p-DE-3iMNW.js +0 -4
  522. package/components/p-DHFt2rdc.js +0 -4
  523. package/components/p-D_RCyzwu.js +0 -4
  524. package/components/p-D_tD8r3L.js +0 -4
  525. package/components/p-DjCtLZbF.js +0 -4
  526. package/components/p-Dmd2xqCe.js +0 -4
  527. package/components/p-G6JR-cr_.js +0 -4
  528. package/components/p-GG5GhznE.js +0 -4
  529. package/components/p-TXPDHL13.js +0 -4
  530. package/components/p-_IKFD3ID.js +0 -4
  531. package/components/p-dKq2jIum.js +0 -4
  532. package/components/p-iYhH60Tc.js +0 -4
  533. package/dist/ionic/p-06ec7136.entry.js +0 -4
  534. package/dist/ionic/p-09fe4fa3.entry.js +0 -4
  535. package/dist/ionic/p-10d45a07.entry.js +0 -4
  536. package/dist/ionic/p-208c8a07.entry.js +0 -4
  537. package/dist/ionic/p-212474fa.entry.js +0 -4
  538. package/dist/ionic/p-2eef1396.entry.js +0 -4
  539. package/dist/ionic/p-347e005d.entry.js +0 -4
  540. package/dist/ionic/p-3a0b3f1d.entry.js +0 -4
  541. package/dist/ionic/p-3b071259.entry.js +0 -4
  542. package/dist/ionic/p-4204184c.entry.js +0 -4
  543. package/dist/ionic/p-47464391.entry.js +0 -4
  544. package/dist/ionic/p-4f9c9126.entry.js +0 -4
  545. package/dist/ionic/p-5JsKPLJD.js +0 -4
  546. package/dist/ionic/p-5bc485c6.entry.js +0 -4
  547. package/dist/ionic/p-603a61e6.entry.js +0 -4
  548. package/dist/ionic/p-60576951.entry.js +0 -4
  549. package/dist/ionic/p-67a81d33.entry.js +0 -4
  550. package/dist/ionic/p-6affb775.entry.js +0 -4
  551. package/dist/ionic/p-6f120c25.entry.js +0 -4
  552. package/dist/ionic/p-71c82b60.entry.js +0 -4
  553. package/dist/ionic/p-79325ffe.entry.js +0 -4
  554. package/dist/ionic/p-7e4d51fa.entry.js +0 -4
  555. package/dist/ionic/p-7f5d4664.entry.js +0 -4
  556. package/dist/ionic/p-80ee82fc.entry.js +0 -4
  557. package/dist/ionic/p-84af7dbc.entry.js +0 -4
  558. package/dist/ionic/p-89ca830a.entry.js +0 -4
  559. package/dist/ionic/p-93b8ec8f.entry.js +0 -4
  560. package/dist/ionic/p-946f65c2.entry.js +0 -4
  561. package/dist/ionic/p-9c4b39fb.entry.js +0 -4
  562. package/dist/ionic/p-B1NEZUzQ.js +0 -4
  563. package/dist/ionic/p-B1ck5iy-.js +0 -4
  564. package/dist/ionic/p-B4FrqdW0.js +0 -4
  565. package/dist/ionic/p-C-94tAim.js +0 -4
  566. package/dist/ionic/p-C-eHZMYE.js +0 -4
  567. package/dist/ionic/p-CaRuIadB.js +0 -4
  568. package/dist/ionic/p-ChhhtsGZ.js +0 -5
  569. package/dist/ionic/p-CzS1qWve.js +0 -4
  570. package/dist/ionic/p-DjjfauRM.js +0 -4
  571. package/dist/ionic/p-DkUB-ROc.js +0 -4
  572. package/dist/ionic/p-DplOqGUv.js +0 -4
  573. package/dist/ionic/p-Dst_XmZh.js +0 -4
  574. package/dist/ionic/p-TXPDHL13.js +0 -4
  575. package/dist/ionic/p-a438b193.entry.js +0 -4
  576. package/dist/ionic/p-babaaaa7.entry.js +0 -4
  577. package/dist/ionic/p-be08d500.entry.js +0 -4
  578. package/dist/ionic/p-be9a4f51.entry.js +0 -4
  579. package/dist/ionic/p-c00d3092.entry.js +0 -4
  580. package/dist/ionic/p-c36dc8f5.entry.js +0 -4
  581. package/dist/ionic/p-c72a7e17.entry.js +0 -4
  582. package/dist/ionic/p-c8edd88c.entry.js +0 -4
  583. package/dist/ionic/p-ce0e380b.entry.js +0 -4
  584. package/dist/ionic/p-ce32912b.entry.js +0 -4
  585. package/dist/ionic/p-d07cf130.entry.js +0 -4
  586. package/dist/ionic/p-d27edeb3.entry.js +0 -4
  587. package/dist/ionic/p-d5d2c506.entry.js +0 -4
  588. package/dist/ionic/p-d5e31ca9.entry.js +0 -4
  589. package/dist/ionic/p-de91444f.entry.js +0 -4
  590. package/dist/ionic/p-df72866d.entry.js +0 -4
  591. package/dist/ionic/p-e47e3151.entry.js +0 -4
  592. package/dist/ionic/p-e621e5e8.entry.js +0 -4
  593. package/dist/ionic/p-eea9cf93.entry.js +0 -4
  594. package/dist/ionic/p-f402f5a4.entry.js +0 -4
  595. package/dist/ionic/p-fe1bfbcf.entry.js +0 -4
  596. package/dist/ionic/p-ffb90460.entry.js +0 -4
@@ -54,143 +54,782 @@ import { checkForPresentationFormatMismatch, warnIfTimeZoneProvided } from "./ut
54
54
  * @part datetime-selected-date - The element that contains the selected date.
55
55
  */
56
56
  export class Datetime {
57
- inputId = `ion-dt-${datetimeIds++}`;
58
- calendarBodyRef;
59
- popoverRef;
60
- intersectionTrackerRef;
61
- clearFocusVisible;
62
- parsedMinuteValues;
63
- parsedHourValues;
64
- parsedMonthValues;
65
- parsedYearValues;
66
- parsedDayValues;
67
- destroyCalendarListener;
68
- destroyKeyboardMO;
69
- // TODO(FW-2832): types (DatetimeParts causes some errors that need untangling)
70
- minParts;
71
- maxParts;
72
- todayParts;
73
- defaultParts;
74
- loadTimeout;
75
- /**
76
- * Set true only by `visibleCallback`. Lets `hiddenCallback` ignore the
77
- * synthetic "not intersecting" entry IntersectionObserver fires on
78
- * `observe()` when the host mounts offscreen.
79
- *
80
- * Don't reset this in `disconnectedCallback`. Overlays disconnect and
81
- * reconnect the host without re-creating the observers, so a reset there
82
- * makes `hiddenCallback` miss the dismissal.
83
- */
84
- hasBeenIntersecting = false;
85
- prevPresentation = null;
86
- resolveForceDateScrolling;
87
- showMonthAndYear = false;
88
- activeParts = [];
89
- workingParts = {
90
- month: 5,
91
- day: 28,
92
- year: 2021,
93
- hour: 13,
94
- minute: 52,
95
- ampm: 'pm',
96
- isAdjacentDay: false,
97
- };
98
- el;
99
- isTimePopoverOpen = false;
100
- /**
101
- * When defined, will force the datetime to render the month
102
- * containing the specified date. Currently, this should only
103
- * be used to enable immediately auto-scrolling to the new month,
104
- * and should then be reset to undefined once the transition is
105
- * finished and the forced month is now in view.
106
- *
107
- * Applies to grid-style datetimes only.
108
- */
109
- forceRenderDate;
110
- /**
111
- * The color to use from your application's color palette.
112
- * Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`.
113
- * For more information on colors, refer to [theming](/docs/theming/basics).
114
- */
115
- color;
116
- /**
117
- * The name of the control, which is submitted with the form data.
118
- */
119
- name = this.inputId;
120
- /**
121
- * If `true`, the user cannot interact with the datetime.
122
- */
123
- disabled = false;
124
- /**
125
- * Formatting options for dates and times.
126
- * Should include a 'date' and/or 'time' object, each of which is of type [Intl.DateTimeFormatOptions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#options).
127
- *
128
- */
129
- formatOptions;
57
+ constructor() {
58
+ this.inputId = `ion-dt-${datetimeIds++}`;
59
+ /**
60
+ * Set true only by `visibleCallback`. Lets `hiddenCallback` ignore the
61
+ * synthetic "not intersecting" entry IntersectionObserver fires on
62
+ * `observe()` when the host mounts offscreen.
63
+ *
64
+ * Don't reset this in `disconnectedCallback`. Overlays disconnect and
65
+ * reconnect the host without re-creating the observers, so a reset there
66
+ * makes `hiddenCallback` miss the dismissal.
67
+ */
68
+ this.hasBeenIntersecting = false;
69
+ this.prevPresentation = null;
70
+ this.showMonthAndYear = false;
71
+ this.activeParts = [];
72
+ this.workingParts = {
73
+ month: 5,
74
+ day: 28,
75
+ year: 2021,
76
+ hour: 13,
77
+ minute: 52,
78
+ ampm: 'pm',
79
+ isAdjacentDay: false,
80
+ };
81
+ this.isTimePopoverOpen = false;
82
+ /**
83
+ * The name of the control, which is submitted with the form data.
84
+ */
85
+ this.name = this.inputId;
86
+ /**
87
+ * If `true`, the user cannot interact with the datetime.
88
+ */
89
+ this.disabled = false;
90
+ /**
91
+ * If `true`, the datetime appears normal but the selected date cannot be changed.
92
+ */
93
+ this.readonly = false;
94
+ /**
95
+ * If `true`, the datetime calendar displays a six-week (42-day) layout,
96
+ * including days from the previous and next months to fill the grid.
97
+ * These adjacent days are selectable unless disabled.
98
+ */
99
+ this.showAdjacentDays = false;
100
+ /**
101
+ * Which values you want to select. `"date"` will show
102
+ * a calendar picker to select the month, day, and year. `"time"`
103
+ * will show a time picker to select the hour, minute, and (optionally)
104
+ * AM/PM. `"date-time"` will show the date picker first and time picker second.
105
+ * `"time-date"` will show the time picker first and date picker second.
106
+ */
107
+ this.presentation = 'date-time';
108
+ /**
109
+ * The text to display on the picker's cancel button.
110
+ */
111
+ this.cancelText = 'Cancel';
112
+ /**
113
+ * The text to display on the picker's "Done" button.
114
+ */
115
+ this.doneText = 'Done';
116
+ /**
117
+ * The text to display on the picker's "Clear" button.
118
+ */
119
+ this.clearText = 'Clear';
120
+ /**
121
+ * The locale to use for `ion-datetime`. This
122
+ * impacts month and day name formatting.
123
+ * The `"default"` value refers to the default
124
+ * locale set by your device.
125
+ */
126
+ this.locale = 'default';
127
+ /**
128
+ * The first day of the week to use for `ion-datetime`. The
129
+ * default value is `0` and represents Sunday.
130
+ */
131
+ this.firstDayOfWeek = 0;
132
+ /**
133
+ * If `true`, multiple dates can be selected at once. Only
134
+ * applies to `presentation="date"` and `preferWheel="false"`.
135
+ */
136
+ this.multiple = false;
137
+ /**
138
+ * If `true`, a header will be shown above the calendar
139
+ * picker. This will include both the slotted title, and
140
+ * the selected date.
141
+ */
142
+ this.showDefaultTitle = false;
143
+ /**
144
+ * If `true`, the default "Cancel" and "OK" buttons
145
+ * will be rendered at the bottom of the `ion-datetime`
146
+ * component. Developers can also use the `button` slot
147
+ * if they want to customize these buttons. If custom
148
+ * buttons are set in the `button` slot then the
149
+ * default buttons will not be rendered.
150
+ */
151
+ this.showDefaultButtons = false;
152
+ /**
153
+ * If `true`, a "Clear" button will be rendered alongside
154
+ * the default "Cancel" and "OK" buttons at the bottom of the `ion-datetime`
155
+ * component. Developers can also use the `button` slot
156
+ * if they want to customize these buttons. If custom
157
+ * buttons are set in the `button` slot then the
158
+ * default buttons will not be rendered.
159
+ */
160
+ this.showClearButton = false;
161
+ /**
162
+ * If `true`, the default "Time" label will be rendered
163
+ * for the time selector of the `ion-datetime` component.
164
+ * Developers can also use the `time-label` slot
165
+ * if they want to customize this label. If a custom
166
+ * label is set in the `time-label` slot then the
167
+ * default label will not be rendered.
168
+ */
169
+ this.showDefaultTimeLabel = true;
170
+ /**
171
+ * If `cover`, the `ion-datetime` will expand to cover the full width of its container.
172
+ * If `fixed`, the `ion-datetime` will have a fixed width.
173
+ */
174
+ this.size = 'fixed';
175
+ /**
176
+ * If `true`, a wheel picker will be rendered instead of a calendar grid
177
+ * where possible. If `false`, a calendar grid will be rendered instead of
178
+ * a wheel picker where possible.
179
+ *
180
+ * A wheel picker can be rendered instead of a grid when `presentation` is
181
+ * one of the following values: `"date"`, `"date-time"`, or `"time-date"`.
182
+ *
183
+ * A wheel picker will always be rendered regardless of
184
+ * the `preferWheel` value when `presentation` is one of the following values:
185
+ * `"time"`, `"month"`, `"month-year"`, or `"year"`.
186
+ */
187
+ this.preferWheel = false;
188
+ this.warnIfIncorrectValueUsage = () => {
189
+ const { multiple, value } = this;
190
+ if (!multiple && Array.isArray(value)) {
191
+ /**
192
+ * We do some processing on the `value` array so
193
+ * that it looks more like an array when logged to
194
+ * the console.
195
+ * Example given ['a', 'b']
196
+ * Default toString() behavior: a,b
197
+ * Custom behavior: ['a', 'b']
198
+ */
199
+ printIonWarning(`[ion-datetime] - An array of values was passed, but multiple is "false". This is incorrect usage and may result in unexpected behaviors. To dismiss this warning, pass a string to the "value" property when multiple="false".
200
+
201
+ Value Passed: [${value.map((v) => `'${v}'`).join(', ')}]
202
+ `, this.el);
203
+ }
204
+ };
205
+ this.setValue = (value) => {
206
+ this.value = value;
207
+ this.ionChange.emit({ value });
208
+ };
209
+ /**
210
+ * Returns the DatetimePart interface
211
+ * to use when rendering an initial set of
212
+ * data. This should be used when rendering an
213
+ * interface in an environment where the `value`
214
+ * may not be set. This function works
215
+ * by returning the first selected date and then
216
+ * falling back to defaultParts if no active date
217
+ * is selected.
218
+ */
219
+ this.getActivePartsWithFallback = () => {
220
+ const { defaultParts } = this;
221
+ return this.getActivePart() ?? defaultParts;
222
+ };
223
+ this.getActivePart = () => {
224
+ const { activeParts } = this;
225
+ return Array.isArray(activeParts) ? activeParts[0] : activeParts;
226
+ };
227
+ this.closeParentOverlay = (role) => {
228
+ const popoverOrModal = this.el.closest('ion-modal, ion-popover');
229
+ if (popoverOrModal) {
230
+ popoverOrModal.dismiss(undefined, role);
231
+ }
232
+ };
233
+ this.setWorkingParts = (parts) => {
234
+ this.workingParts = {
235
+ ...parts,
236
+ };
237
+ };
238
+ this.setActiveParts = (parts, removeDate = false) => {
239
+ /** if the datetime component is in readonly mode,
240
+ * allow browsing of the calendar without changing
241
+ * the set value
242
+ */
243
+ if (this.readonly) {
244
+ return;
245
+ }
246
+ const { multiple, minParts, maxParts, activeParts } = this;
247
+ /**
248
+ * When setting the active parts, it is possible
249
+ * to set invalid data. For example,
250
+ * when updating January 31 to February,
251
+ * February 31 does not exist. As a result
252
+ * we need to validate the active parts and
253
+ * ensure that we are only setting valid dates.
254
+ * Additionally, we need to update the working parts
255
+ * too in the event that the validated parts are different.
256
+ */
257
+ const validatedParts = validateParts(parts, minParts, maxParts);
258
+ this.setWorkingParts(validatedParts);
259
+ if (multiple) {
260
+ const activePartsArray = Array.isArray(activeParts) ? activeParts : [activeParts];
261
+ if (removeDate) {
262
+ this.activeParts = activePartsArray.filter((p) => !isSameDay(p, validatedParts));
263
+ }
264
+ else {
265
+ this.activeParts = [...activePartsArray, validatedParts];
266
+ }
267
+ }
268
+ else {
269
+ this.activeParts = {
270
+ ...validatedParts,
271
+ };
272
+ }
273
+ const hasSlottedButtons = this.el.querySelector('[slot="buttons"]') !== null;
274
+ if (hasSlottedButtons || this.showDefaultButtons) {
275
+ return;
276
+ }
277
+ this.confirm();
278
+ };
279
+ this.initializeKeyboardListeners = () => {
280
+ const calendarBodyRef = this.calendarBodyRef;
281
+ if (!calendarBodyRef) {
282
+ return;
283
+ }
284
+ const root = this.el.shadowRoot;
285
+ /**
286
+ * Get a reference to the month
287
+ * element we are currently viewing.
288
+ */
289
+ const currentMonth = calendarBodyRef.querySelector('.calendar-month:nth-of-type(2)');
290
+ /**
291
+ * When focusing the calendar body, we want to pass focus
292
+ * to the working day, but other days should
293
+ * only be accessible using the arrow keys. Pressing
294
+ * Tab should jump between bodies of selectable content.
295
+ */
296
+ const checkCalendarBodyFocus = (ev) => {
297
+ const record = ev[0];
298
+ /**
299
+ * If calendar body was already focused
300
+ * when this fired or if the calendar body
301
+ * if not currently focused, we should not re-focus
302
+ * the inner day.
303
+ */
304
+ if (record.oldValue?.includes('ion-focused') || !calendarBodyRef.classList.contains('ion-focused')) {
305
+ return;
306
+ }
307
+ this.focusWorkingDay(currentMonth);
308
+ };
309
+ const mo = new MutationObserver(checkCalendarBodyFocus);
310
+ mo.observe(calendarBodyRef, { attributeFilter: ['class'], attributeOldValue: true });
311
+ this.destroyKeyboardMO = () => {
312
+ mo?.disconnect();
313
+ };
314
+ /**
315
+ * We must use keydown not keyup as we want
316
+ * to prevent scrolling when using the arrow keys.
317
+ */
318
+ calendarBodyRef.addEventListener('keydown', (ev) => {
319
+ const activeElement = root.activeElement;
320
+ if (!activeElement || !activeElement.classList.contains('calendar-day')) {
321
+ return;
322
+ }
323
+ const parts = getPartsFromCalendarDay(activeElement);
324
+ let partsToFocus;
325
+ switch (ev.key) {
326
+ case 'ArrowDown':
327
+ ev.preventDefault();
328
+ partsToFocus = getNextWeek(parts);
329
+ break;
330
+ case 'ArrowUp':
331
+ ev.preventDefault();
332
+ partsToFocus = getPreviousWeek(parts);
333
+ break;
334
+ case 'ArrowRight':
335
+ ev.preventDefault();
336
+ partsToFocus = getNextDay(parts);
337
+ break;
338
+ case 'ArrowLeft':
339
+ ev.preventDefault();
340
+ partsToFocus = getPreviousDay(parts);
341
+ break;
342
+ case 'Home':
343
+ ev.preventDefault();
344
+ partsToFocus = getStartOfWeek(parts);
345
+ break;
346
+ case 'End':
347
+ ev.preventDefault();
348
+ partsToFocus = getEndOfWeek(parts);
349
+ break;
350
+ case 'PageUp':
351
+ ev.preventDefault();
352
+ partsToFocus = ev.shiftKey ? getPreviousYear(parts) : getPreviousMonth(parts);
353
+ break;
354
+ case 'PageDown':
355
+ ev.preventDefault();
356
+ partsToFocus = ev.shiftKey ? getNextYear(parts) : getNextMonth(parts);
357
+ break;
358
+ /**
359
+ * Do not preventDefault here
360
+ * as we do not want to override other
361
+ * browser defaults such as pressing Enter/Space
362
+ * to select a day.
363
+ */
364
+ default:
365
+ return;
366
+ }
367
+ /**
368
+ * If the day we want to move focus to is
369
+ * disabled, do not do anything.
370
+ */
371
+ if (isDayDisabled(partsToFocus, this.minParts, this.maxParts)) {
372
+ return;
373
+ }
374
+ this.setWorkingParts({
375
+ ...this.workingParts,
376
+ ...partsToFocus,
377
+ });
378
+ /**
379
+ * Give view a chance to re-render
380
+ * then move focus to the new working day
381
+ */
382
+ requestAnimationFrame(() => this.focusWorkingDay(currentMonth));
383
+ });
384
+ };
385
+ this.focusWorkingDay = (currentMonth) => {
386
+ /**
387
+ * Get the number of offset days so
388
+ * we know how much to offset our next selector by
389
+ * to grab the correct calendar-day element.
390
+ */
391
+ const { day, month, year } = this.workingParts;
392
+ const firstOfMonth = new Date(`${month}/1/${year}`).getDay();
393
+ const offset = firstOfMonth >= this.firstDayOfWeek
394
+ ? firstOfMonth - this.firstDayOfWeek
395
+ : 7 - (this.firstDayOfWeek - firstOfMonth);
396
+ if (day === null) {
397
+ return;
398
+ }
399
+ /**
400
+ * Get the calendar day element
401
+ * and focus it.
402
+ */
403
+ const dayEl = currentMonth.querySelector(`.calendar-day-wrapper:nth-of-type(${offset + day}) .calendar-day`);
404
+ if (dayEl) {
405
+ dayEl.focus();
406
+ }
407
+ };
408
+ this.processMinParts = () => {
409
+ const { min, defaultParts } = this;
410
+ if (min === undefined) {
411
+ this.minParts = undefined;
412
+ return;
413
+ }
414
+ this.minParts = parseMinParts(min, defaultParts);
415
+ };
416
+ this.processMaxParts = () => {
417
+ const { max, defaultParts } = this;
418
+ if (max === undefined) {
419
+ this.maxParts = undefined;
420
+ return;
421
+ }
422
+ this.maxParts = parseMaxParts(max, defaultParts);
423
+ };
424
+ this.initializeCalendarListener = () => {
425
+ const calendarBodyRef = this.calendarBodyRef;
426
+ if (!calendarBodyRef) {
427
+ return;
428
+ }
429
+ /**
430
+ * For performance reasons, we only render 3
431
+ * months at a time: The current month, the previous
432
+ * month, and the next month. We have a scroll listener
433
+ * on the calendar body to append/prepend new months.
434
+ *
435
+ * We can do this because Stencil is smart enough to not
436
+ * re-create the .calendar-month containers, but rather
437
+ * update the content within those containers.
438
+ *
439
+ * As an added bonus, WebKit has some troubles with
440
+ * scroll-snap-stop: always, so not rendering all of
441
+ * the months in a row allows us to mostly sidestep
442
+ * that issue.
443
+ */
444
+ const months = calendarBodyRef.querySelectorAll('.calendar-month');
445
+ const startMonth = months[0];
446
+ const workingMonth = months[1];
447
+ const endMonth = months[2];
448
+ const mode = getIonMode(this);
449
+ const needsiOSRubberBandFix = mode === 'ios' && typeof navigator !== 'undefined' && navigator.maxTouchPoints > 1;
450
+ /**
451
+ * Before setting up the scroll listener,
452
+ * scroll the middle month into view.
453
+ * scrollIntoView() will scroll entire page
454
+ * if element is not in viewport. Use scrollLeft instead.
455
+ */
456
+ writeTask(() => {
457
+ calendarBodyRef.scrollLeft = startMonth.clientWidth * (isRTL(this.el) ? -1 : 1);
458
+ const getChangedMonth = (parts) => {
459
+ const box = calendarBodyRef.getBoundingClientRect();
460
+ /**
461
+ * If the current scroll position is all the way to the left
462
+ * then we have scrolled to the previous month.
463
+ * Otherwise, assume that we have scrolled to the next
464
+ * month. We have a tolerance of 2px to account for
465
+ * sub pixel rendering.
466
+ *
467
+ * Check below the next line ensures that we did not
468
+ * swipe and abort (i.e. we swiped but we are still on the current month).
469
+ */
470
+ const condition = isRTL(this.el) ? calendarBodyRef.scrollLeft >= -2 : calendarBodyRef.scrollLeft <= 2;
471
+ const month = condition ? startMonth : endMonth;
472
+ /**
473
+ * The edge of the month must be lined up with
474
+ * the edge of the calendar body in order for
475
+ * the component to update. Otherwise, it
476
+ * may be the case that the user has paused their
477
+ * swipe or the browser has not finished snapping yet.
478
+ * Rather than check if the x values are equal,
479
+ * we give it a tolerance of 2px to account for
480
+ * sub pixel rendering.
481
+ */
482
+ const monthBox = month.getBoundingClientRect();
483
+ if (Math.abs(monthBox.x - box.x) > 2)
484
+ return;
485
+ /**
486
+ * If we're force-rendering a month, assume we've
487
+ * scrolled to that and return it.
488
+ *
489
+ * If forceRenderDate is ever used in a context where the
490
+ * forced month is not immediately auto-scrolled to, this
491
+ * should be updated to also check whether `month` has the
492
+ * same month and year as the forced date.
493
+ */
494
+ const { forceRenderDate } = this;
495
+ if (forceRenderDate !== undefined) {
496
+ return { month: forceRenderDate.month, year: forceRenderDate.year, day: forceRenderDate.day };
497
+ }
498
+ /**
499
+ * From here, we can determine if the start
500
+ * month or the end month was scrolled into view.
501
+ * If no month was changed, then we can return from
502
+ * the scroll callback early.
503
+ */
504
+ if (month === startMonth) {
505
+ return getPreviousMonth(parts);
506
+ }
507
+ else if (month === endMonth) {
508
+ return getNextMonth(parts);
509
+ }
510
+ else {
511
+ return;
512
+ }
513
+ };
514
+ const updateActiveMonth = () => {
515
+ if (needsiOSRubberBandFix) {
516
+ calendarBodyRef.style.removeProperty('pointer-events');
517
+ appliediOSRubberBandFix = false;
518
+ }
519
+ /**
520
+ * If the month did not change
521
+ * then we can return early.
522
+ */
523
+ const newDate = getChangedMonth(this.workingParts);
524
+ if (!newDate)
525
+ return;
526
+ const { month, day, year } = newDate;
527
+ if (isMonthDisabled({ month, year, day: null }, {
528
+ minParts: { ...this.minParts, day: null },
529
+ maxParts: { ...this.maxParts, day: null },
530
+ })) {
531
+ return;
532
+ }
533
+ /**
534
+ * Prevent scrolling for other browsers
535
+ * to give the DOM time to update and the container
536
+ * time to properly snap.
537
+ */
538
+ calendarBodyRef.style.setProperty('overflow', 'hidden');
539
+ /**
540
+ * Use a writeTask here to ensure
541
+ * that the state is updated and the
542
+ * correct month is scrolled into view
543
+ * in the same frame. This is not
544
+ * typically a problem on newer devices
545
+ * but older/slower device may have a flicker
546
+ * if we did not do this.
547
+ */
548
+ writeTask(() => {
549
+ this.setWorkingParts({
550
+ ...this.workingParts,
551
+ month,
552
+ day: day,
553
+ year,
554
+ });
555
+ calendarBodyRef.scrollLeft = workingMonth.clientWidth * (isRTL(this.el) ? -1 : 1);
556
+ calendarBodyRef.style.removeProperty('overflow');
557
+ if (this.resolveForceDateScrolling) {
558
+ this.resolveForceDateScrolling();
559
+ }
560
+ const activeEl = this.el.shadowRoot.activeElement;
561
+ if (activeEl && activeEl.classList.contains('calendar-day')) {
562
+ activeEl.closest('.calendar-body')?.focus();
563
+ }
564
+ });
565
+ };
566
+ /**
567
+ * When the container finishes scrolling we
568
+ * need to update the DOM with the selected month.
569
+ */
570
+ let scrollTimeout;
571
+ /**
572
+ * We do not want to attempt to set pointer-events
573
+ * multiple times within a single swipe gesture as
574
+ * that adds unnecessary work to the main thread.
575
+ */
576
+ let appliediOSRubberBandFix = false;
577
+ const scrollCallback = () => {
578
+ if (scrollTimeout) {
579
+ clearTimeout(scrollTimeout);
580
+ }
581
+ /**
582
+ * On iOS it is possible to quickly rubber band
583
+ * the scroll area before the scroll timeout has fired.
584
+ * This results in users reaching the end of the scrollable
585
+ * container before the DOM has updated.
586
+ * By setting `pointer-events: none` we can ensure that
587
+ * subsequent swipes do not happen while the container
588
+ * is snapping.
589
+ */
590
+ if (!appliediOSRubberBandFix && needsiOSRubberBandFix) {
591
+ calendarBodyRef.style.setProperty('pointer-events', 'none');
592
+ appliediOSRubberBandFix = true;
593
+ }
594
+ // Wait ~3 frames
595
+ scrollTimeout = setTimeout(updateActiveMonth, 50);
596
+ };
597
+ calendarBodyRef.addEventListener('scroll', scrollCallback);
598
+ this.destroyCalendarListener = () => {
599
+ calendarBodyRef.removeEventListener('scroll', scrollCallback);
600
+ };
601
+ });
602
+ };
603
+ /**
604
+ * Clean up all listeners except for the overlay
605
+ * listener. This is so that we can re-create the listeners
606
+ * if the datetime has been hidden/presented by a modal or popover.
607
+ */
608
+ this.destroyInteractionListeners = () => {
609
+ const { destroyCalendarListener, destroyKeyboardMO } = this;
610
+ if (destroyCalendarListener !== undefined) {
611
+ destroyCalendarListener();
612
+ }
613
+ if (destroyKeyboardMO !== undefined) {
614
+ destroyKeyboardMO();
615
+ }
616
+ };
617
+ /**
618
+ * TODO(FW-6931): Remove this fallback upon solving the root cause
619
+ * Fallback to ensure the datetime becomes ready even if
620
+ * IntersectionObserver never reports it as intersecting.
621
+ *
622
+ * This is primarily used in environments where the observer
623
+ * might not fire as expected, such as when running under
624
+ * synthetic tests that stub IntersectionObserver.
625
+ */
626
+ this.ensureReadyIfVisible = () => {
627
+ if (this.el.classList.contains('datetime-ready')) {
628
+ return;
629
+ }
630
+ const rect = this.el.getBoundingClientRect();
631
+ if (rect.width === 0 || rect.height === 0) {
632
+ return;
633
+ }
634
+ this.markReady();
635
+ };
636
+ this.markReady = () => {
637
+ if (this.el.classList.contains('datetime-ready')) {
638
+ return;
639
+ }
640
+ this.initializeListeners();
641
+ /**
642
+ * TODO FW-2793: Datetime needs a frame to ensure that it
643
+ * can properly scroll contents into view. As a result
644
+ * we hide the scrollable content until after that frame
645
+ * so users do not see the content quickly shifting. The downside
646
+ * is that the content will pop into view a frame after. Maybe there
647
+ * is a better way to handle this?
648
+ */
649
+ writeTask(() => {
650
+ this.el.classList.add('datetime-ready');
651
+ });
652
+ };
653
+ this.loadTimeoutCleanup = () => {
654
+ if (this.loadTimeout) {
655
+ clearTimeout(this.loadTimeout);
656
+ this.loadTimeout = undefined;
657
+ }
658
+ };
659
+ this.processValue = (value) => {
660
+ const hasValue = value !== null && value !== undefined && value !== '' && (!Array.isArray(value) || value.length > 0);
661
+ const valueToProcess = hasValue ? parseDate(value) : this.defaultParts;
662
+ const { minParts, maxParts, workingParts, el } = this;
663
+ this.warnIfIncorrectValueUsage();
664
+ /**
665
+ * Return early if the value wasn't parsed correctly, such as
666
+ * if an improperly formatted date string was provided.
667
+ */
668
+ if (!valueToProcess) {
669
+ return;
670
+ }
671
+ /**
672
+ * Datetime should only warn of out of bounds values
673
+ * if set by the user. If the `value` is undefined,
674
+ * we will default to today's date which may be out
675
+ * of bounds. In this case, the warning makes it look
676
+ * like the developer did something wrong which is
677
+ * not true.
678
+ */
679
+ if (hasValue) {
680
+ warnIfValueOutOfBounds(valueToProcess, minParts, maxParts);
681
+ }
682
+ /**
683
+ * If there are multiple values, clamp to the last one.
684
+ * This is because the last value is the one that the user
685
+ * has most recently interacted with.
686
+ */
687
+ const singleValue = Array.isArray(valueToProcess) ? valueToProcess[valueToProcess.length - 1] : valueToProcess;
688
+ const targetValue = clampDate(singleValue, minParts, maxParts);
689
+ const { month, day, year, hour, minute } = targetValue;
690
+ const ampm = parseAmPm(hour);
691
+ /**
692
+ * Since `activeParts` indicates a value that been explicitly selected
693
+ * either by the user or the app, only update `activeParts` if the
694
+ * `value` property is set.
695
+ */
696
+ if (hasValue) {
697
+ if (Array.isArray(valueToProcess)) {
698
+ this.activeParts = [...valueToProcess];
699
+ }
700
+ else {
701
+ this.activeParts = {
702
+ month,
703
+ day,
704
+ year,
705
+ hour,
706
+ minute,
707
+ ampm,
708
+ };
709
+ }
710
+ }
711
+ else {
712
+ /**
713
+ * Reset the active parts if the value is not set.
714
+ * This will clear the selected calendar day when
715
+ * performing a clear action or using the reset() method.
716
+ */
717
+ this.activeParts = [];
718
+ }
719
+ const didChangeMonth = (month !== undefined && month !== workingParts.month) || (year !== undefined && year !== workingParts.year);
720
+ const bodyIsVisible = el.classList.contains('datetime-ready');
721
+ const { isGridStyle, showMonthAndYear } = this;
722
+ if (isGridStyle && didChangeMonth && bodyIsVisible && !showMonthAndYear) {
723
+ /**
724
+ * Only animate if:
725
+ * 1. We're using grid style (wheel style pickers should just jump to new value)
726
+ * 2. The month and/or year actually changed, and both are defined (otherwise there's nothing to animate to)
727
+ * 3. The calendar body is visible (prevents animation when in collapsed datetime-button, for example)
728
+ * 4. The month/year picker is not open (since you wouldn't see the animation anyway)
729
+ */
730
+ this.animateToDate(targetValue);
731
+ }
732
+ else {
733
+ this.setWorkingParts({
734
+ month,
735
+ day,
736
+ year,
737
+ hour,
738
+ minute,
739
+ ampm,
740
+ });
741
+ }
742
+ };
743
+ this.animateToDate = async (targetValue) => {
744
+ const { workingParts } = this;
745
+ /**
746
+ * Tell other render functions that we need to force the
747
+ * target month to appear in place of the actual next/prev month.
748
+ * Because this is a State variable, a rerender will be triggered
749
+ * automatically, updating the rendered months.
750
+ */
751
+ this.forceRenderDate = targetValue;
752
+ /**
753
+ * Flag that we've started scrolling to the forced date.
754
+ * The resolve function will be called by the datetime's
755
+ * scroll listener when it's done updating everything.
756
+ * This is a replacement for making prev/nextMonth async,
757
+ * since the logic we're waiting on is in a listener.
758
+ */
759
+ const forceDateScrollingPromise = new Promise((resolve) => {
760
+ this.resolveForceDateScrolling = resolve;
761
+ });
762
+ /**
763
+ * Animate smoothly to the forced month. This will also update
764
+ * workingParts and correct the surrounding months for us.
765
+ */
766
+ const targetMonthIsBefore = isBefore(targetValue, workingParts);
767
+ targetMonthIsBefore ? this.prevMonth() : this.nextMonth();
768
+ await forceDateScrollingPromise;
769
+ this.resolveForceDateScrolling = undefined;
770
+ this.forceRenderDate = undefined;
771
+ };
772
+ this.onFocus = () => {
773
+ this.ionFocus.emit();
774
+ };
775
+ this.onBlur = () => {
776
+ this.ionBlur.emit();
777
+ };
778
+ this.hasValue = () => {
779
+ return this.value != null;
780
+ };
781
+ this.nextMonth = () => {
782
+ const calendarBodyRef = this.calendarBodyRef;
783
+ if (!calendarBodyRef) {
784
+ return;
785
+ }
786
+ const nextMonth = calendarBodyRef.querySelector('.calendar-month:last-of-type');
787
+ if (!nextMonth) {
788
+ return;
789
+ }
790
+ const left = nextMonth.offsetWidth * 2;
791
+ const scrollMode = config.getBoolean('animated', true) ? 'smooth' : 'instant';
792
+ calendarBodyRef.scrollTo({
793
+ top: 0,
794
+ left: left * (isRTL(this.el) ? -1 : 1),
795
+ behavior: scrollMode,
796
+ });
797
+ };
798
+ this.prevMonth = () => {
799
+ const calendarBodyRef = this.calendarBodyRef;
800
+ if (!calendarBodyRef) {
801
+ return;
802
+ }
803
+ const prevMonth = calendarBodyRef.querySelector('.calendar-month:first-of-type');
804
+ if (!prevMonth) {
805
+ return;
806
+ }
807
+ const left = prevMonth.offsetWidth * 2;
808
+ const scrollMode = config.getBoolean('animated', true) ? 'smooth' : 'instant';
809
+ calendarBodyRef.scrollTo({
810
+ top: 0,
811
+ left: left * (isRTL(this.el) ? 1 : -1),
812
+ behavior: scrollMode,
813
+ });
814
+ };
815
+ this.toggleMonthAndYearView = () => {
816
+ this.showMonthAndYear = !this.showMonthAndYear;
817
+ };
818
+ }
130
819
  formatOptionsChanged() {
131
820
  const { el, formatOptions, presentation } = this;
132
821
  checkForPresentationFormatMismatch(el, presentation, formatOptions);
133
822
  warnIfTimeZoneProvided(el, formatOptions);
134
823
  }
135
- /**
136
- * If `true`, the datetime appears normal but the selected date cannot be changed.
137
- */
138
- readonly = false;
139
- /**
140
- * Returns if an individual date (calendar day) is enabled or disabled.
141
- *
142
- * If `true`, the day will be enabled/interactive.
143
- * If `false`, the day will be disabled/non-interactive.
144
- *
145
- * The function accepts an ISO 8601 date string of a given day.
146
- * By default, all days are enabled. Developers can use this function
147
- * to write custom logic to disable certain days.
148
- *
149
- * The function is called for each rendered calendar day, for the previous, current and next month.
150
- * Custom implementations should be optimized for performance to avoid jank.
151
- */
152
- isDateEnabled;
153
- /**
154
- * If `true`, the datetime calendar displays a six-week (42-day) layout,
155
- * including days from the previous and next months to fill the grid.
156
- * These adjacent days are selectable unless disabled.
157
- */
158
- showAdjacentDays = false;
159
824
  disabledChanged() {
160
825
  this.emitStyle();
161
826
  }
162
- /**
163
- * The minimum datetime allowed. Value must be a date string
164
- * following the
165
- * [ISO 8601 datetime format standard](https://www.w3.org/TR/NOTE-datetime),
166
- * such as `1996-12-19`. The format does not have to be specific to an exact
167
- * datetime. For example, the minimum could just be the year, such as `1994`.
168
- * Defaults to the beginning of the year, 100 years ago from today.
169
- */
170
- min;
171
827
  minChanged() {
172
828
  this.processMinParts();
173
829
  }
174
- /**
175
- * The maximum datetime allowed. Value must be a date string
176
- * following the
177
- * [ISO 8601 datetime format standard](https://www.w3.org/TR/NOTE-datetime),
178
- * `1996-12-19`. The format does not have to be specific to an exact
179
- * datetime. For example, the maximum could just be the year, such as `1994`.
180
- * Defaults to the end of this year.
181
- */
182
- max;
183
830
  maxChanged() {
184
831
  this.processMaxParts();
185
832
  }
186
- /**
187
- * Which values you want to select. `"date"` will show
188
- * a calendar picker to select the month, day, and year. `"time"`
189
- * will show a time picker to select the hour, minute, and (optionally)
190
- * AM/PM. `"date-time"` will show the date picker first and time picker second.
191
- * `"time-date"` will show the time picker first and date picker second.
192
- */
193
- presentation = 'date-time';
194
833
  presentationChanged() {
195
834
  const { el, formatOptions, presentation } = this;
196
835
  checkForPresentationFormatMismatch(el, presentation, formatOptions);
@@ -200,116 +839,21 @@ export class Datetime {
200
839
  const hasDatePresentation = presentation === 'date' || presentation === 'date-time' || presentation === 'time-date';
201
840
  return hasDatePresentation && !preferWheel;
202
841
  }
203
- /**
204
- * The text to display on the picker's cancel button.
205
- */
206
- cancelText = 'Cancel';
207
- /**
208
- * The text to display on the picker's "Done" button.
209
- */
210
- doneText = 'Done';
211
- /**
212
- * The text to display on the picker's "Clear" button.
213
- */
214
- clearText = 'Clear';
215
- /**
216
- * Values used to create the list of selectable years. By default
217
- * the year values range between the `min` and `max` datetime inputs. However, to
218
- * control exactly which years to display, the `yearValues` input can take a number, an array
219
- * of numbers, or string of comma separated numbers. For example, to show upcoming and
220
- * recent leap years, then this input's value would be `yearValues="2008,2012,2016,2020,2024"`.
221
- */
222
- yearValues;
223
842
  yearValuesChanged() {
224
843
  this.parsedYearValues = convertToArrayOfNumbers(this.yearValues);
225
844
  }
226
- /**
227
- * Values used to create the list of selectable months. By default
228
- * the month values range from `1` to `12`. However, to control exactly which months to
229
- * display, the `monthValues` input can take a number, an array of numbers, or a string of
230
- * comma separated numbers. For example, if only summer months should be shown, then this
231
- * input value would be `monthValues="6,7,8"`. Note that month numbers do *not* have a
232
- * zero-based index, meaning January's value is `1`, and December's is `12`.
233
- */
234
- monthValues;
235
845
  monthValuesChanged() {
236
846
  this.parsedMonthValues = convertToArrayOfNumbers(this.monthValues);
237
847
  }
238
- /**
239
- * Values used to create the list of selectable days. By default
240
- * every day is shown for the given month. However, to control exactly which days of
241
- * the month to display, the `dayValues` input can take a number, an array of numbers, or
242
- * a string of comma separated numbers. Note that even if the array days have an invalid
243
- * number for the selected month, like `31` in February, it will correctly not show
244
- * days which are not valid for the selected month.
245
- */
246
- dayValues;
247
848
  dayValuesChanged() {
248
849
  this.parsedDayValues = convertToArrayOfNumbers(this.dayValues);
249
850
  }
250
- /**
251
- * Values used to create the list of selectable hours. By default
252
- * the hour values range from `0` to `23` for 24-hour, or `1` to `12` for 12-hour. However,
253
- * to control exactly which hours to display, the `hourValues` input can take a number, an
254
- * array of numbers, or a string of comma separated numbers.
255
- */
256
- hourValues;
257
851
  hourValuesChanged() {
258
852
  this.parsedHourValues = convertToArrayOfNumbers(this.hourValues);
259
853
  }
260
- /**
261
- * Values used to create the list of selectable minutes. By default
262
- * the minutes range from `0` to `59`. However, to control exactly which minutes to display,
263
- * the `minuteValues` input can take a number, an array of numbers, or a string of comma
264
- * separated numbers. For example, if the minute selections should only be every 15 minutes,
265
- * then this input value would be `minuteValues="0,15,30,45"`.
266
- */
267
- minuteValues;
268
854
  minuteValuesChanged() {
269
855
  this.parsedMinuteValues = convertToArrayOfNumbers(this.minuteValues);
270
856
  }
271
- /**
272
- * The locale to use for `ion-datetime`. This
273
- * impacts month and day name formatting.
274
- * The `"default"` value refers to the default
275
- * locale set by your device.
276
- */
277
- locale = 'default';
278
- /**
279
- * The first day of the week to use for `ion-datetime`. The
280
- * default value is `0` and represents Sunday.
281
- */
282
- firstDayOfWeek = 0;
283
- /**
284
- * A callback used to format the header text that shows how many
285
- * dates are selected. Only used if there are 0 or more than 1
286
- * selected (i.e. unused for exactly 1). By default, the header
287
- * text is set to "numberOfDates days".
288
- *
289
- * See https://ionicframework.com/docs/troubleshooting/runtime#accessing-this
290
- * if you need to access `this` from within the callback.
291
- */
292
- titleSelectedDatesFormatter;
293
- /**
294
- * If `true`, multiple dates can be selected at once. Only
295
- * applies to `presentation="date"` and `preferWheel="false"`.
296
- */
297
- multiple = false;
298
- /**
299
- * Used to apply custom text and background colors to specific dates.
300
- *
301
- * Can be either an array of objects containing ISO strings and colors,
302
- * or a callback that receives an ISO string and returns the colors.
303
- *
304
- * Only applies to the `date`, `date-time`, and `time-date` presentations,
305
- * with `preferWheel="false"`.
306
- */
307
- highlightedDates;
308
- /**
309
- * The value of the datetime as a valid ISO 8601 datetime string.
310
- * This should be an array of strings only when `multiple="true"`.
311
- */
312
- value;
313
857
  /**
314
858
  * Update the datetime value when the value changes
315
859
  */
@@ -321,97 +865,6 @@ export class Datetime {
321
865
  this.emitStyle();
322
866
  this.ionValueChange.emit({ value });
323
867
  }
324
- /**
325
- * If `true`, a header will be shown above the calendar
326
- * picker. This will include both the slotted title, and
327
- * the selected date.
328
- */
329
- showDefaultTitle = false;
330
- /**
331
- * If `true`, the default "Cancel" and "OK" buttons
332
- * will be rendered at the bottom of the `ion-datetime`
333
- * component. Developers can also use the `button` slot
334
- * if they want to customize these buttons. If custom
335
- * buttons are set in the `button` slot then the
336
- * default buttons will not be rendered.
337
- */
338
- showDefaultButtons = false;
339
- /**
340
- * If `true`, a "Clear" button will be rendered alongside
341
- * the default "Cancel" and "OK" buttons at the bottom of the `ion-datetime`
342
- * component. Developers can also use the `button` slot
343
- * if they want to customize these buttons. If custom
344
- * buttons are set in the `button` slot then the
345
- * default buttons will not be rendered.
346
- */
347
- showClearButton = false;
348
- /**
349
- * If `true`, the default "Time" label will be rendered
350
- * for the time selector of the `ion-datetime` component.
351
- * Developers can also use the `time-label` slot
352
- * if they want to customize this label. If a custom
353
- * label is set in the `time-label` slot then the
354
- * default label will not be rendered.
355
- */
356
- showDefaultTimeLabel = true;
357
- /**
358
- * The hour cycle of the `ion-datetime`. If no value is set, this is
359
- * specified by the current locale.
360
- */
361
- hourCycle;
362
- /**
363
- * If `cover`, the `ion-datetime` will expand to cover the full width of its container.
364
- * If `fixed`, the `ion-datetime` will have a fixed width.
365
- */
366
- size = 'fixed';
367
- /**
368
- * If `true`, a wheel picker will be rendered instead of a calendar grid
369
- * where possible. If `false`, a calendar grid will be rendered instead of
370
- * a wheel picker where possible.
371
- *
372
- * A wheel picker can be rendered instead of a grid when `presentation` is
373
- * one of the following values: `"date"`, `"date-time"`, or `"time-date"`.
374
- *
375
- * A wheel picker will always be rendered regardless of
376
- * the `preferWheel` value when `presentation` is one of the following values:
377
- * `"time"`, `"month"`, `"month-year"`, or `"year"`.
378
- */
379
- preferWheel = false;
380
- /**
381
- * Emitted when the datetime selection was cancelled.
382
- */
383
- ionCancel;
384
- /**
385
- * Emitted when the value (selected date) has changed.
386
- *
387
- * This event will not emit when programmatically setting the `value` property.
388
- */
389
- ionChange;
390
- /**
391
- * Emitted when the value property has changed.
392
- * This is used to ensure that ion-datetime-button can respond
393
- * to any value property changes.
394
- * @internal
395
- */
396
- ionValueChange;
397
- /**
398
- * Emitted when the datetime has focus.
399
- */
400
- ionFocus;
401
- /**
402
- * Emitted when the datetime loses focus.
403
- */
404
- ionBlur;
405
- /**
406
- * Emitted when the styles change.
407
- * @internal
408
- */
409
- ionStyle;
410
- /**
411
- * Emitted when componentDidRender is fired.
412
- * @internal
413
- */
414
- ionRender;
415
868
  /**
416
869
  * Confirms the selected datetime value, updates the
417
870
  * `value` property, and optionally closes the popover
@@ -481,425 +934,10 @@ export class Datetime {
481
934
  async getDefaultPart() {
482
935
  return this.defaultParts;
483
936
  }
484
- warnIfIncorrectValueUsage = () => {
485
- const { multiple, value } = this;
486
- if (!multiple && Array.isArray(value)) {
487
- /**
488
- * We do some processing on the `value` array so
489
- * that it looks more like an array when logged to
490
- * the console.
491
- * Example given ['a', 'b']
492
- * Default toString() behavior: a,b
493
- * Custom behavior: ['a', 'b']
494
- */
495
- printIonWarning(`[ion-datetime] - An array of values was passed, but multiple is "false". This is incorrect usage and may result in unexpected behaviors. To dismiss this warning, pass a string to the "value" property when multiple="false".
496
-
497
- Value Passed: [${value.map((v) => `'${v}'`).join(', ')}]
498
- `, this.el);
499
- }
500
- };
501
- setValue = (value) => {
502
- this.value = value;
503
- this.ionChange.emit({ value });
504
- };
505
- /**
506
- * Returns the DatetimePart interface
507
- * to use when rendering an initial set of
508
- * data. This should be used when rendering an
509
- * interface in an environment where the `value`
510
- * may not be set. This function works
511
- * by returning the first selected date and then
512
- * falling back to defaultParts if no active date
513
- * is selected.
514
- */
515
- getActivePartsWithFallback = () => {
516
- const { defaultParts } = this;
517
- return this.getActivePart() ?? defaultParts;
518
- };
519
- getActivePart = () => {
520
- const { activeParts } = this;
521
- return Array.isArray(activeParts) ? activeParts[0] : activeParts;
522
- };
523
- closeParentOverlay = (role) => {
524
- const popoverOrModal = this.el.closest('ion-modal, ion-popover');
525
- if (popoverOrModal) {
526
- popoverOrModal.dismiss(undefined, role);
527
- }
528
- };
529
- setWorkingParts = (parts) => {
530
- this.workingParts = {
531
- ...parts,
532
- };
533
- };
534
- setActiveParts = (parts, removeDate = false) => {
535
- /** if the datetime component is in readonly mode,
536
- * allow browsing of the calendar without changing
537
- * the set value
538
- */
539
- if (this.readonly) {
540
- return;
541
- }
542
- const { multiple, minParts, maxParts, activeParts } = this;
543
- /**
544
- * When setting the active parts, it is possible
545
- * to set invalid data. For example,
546
- * when updating January 31 to February,
547
- * February 31 does not exist. As a result
548
- * we need to validate the active parts and
549
- * ensure that we are only setting valid dates.
550
- * Additionally, we need to update the working parts
551
- * too in the event that the validated parts are different.
552
- */
553
- const validatedParts = validateParts(parts, minParts, maxParts);
554
- this.setWorkingParts(validatedParts);
555
- if (multiple) {
556
- const activePartsArray = Array.isArray(activeParts) ? activeParts : [activeParts];
557
- if (removeDate) {
558
- this.activeParts = activePartsArray.filter((p) => !isSameDay(p, validatedParts));
559
- }
560
- else {
561
- this.activeParts = [...activePartsArray, validatedParts];
562
- }
563
- }
564
- else {
565
- this.activeParts = {
566
- ...validatedParts,
567
- };
568
- }
569
- const hasSlottedButtons = this.el.querySelector('[slot="buttons"]') !== null;
570
- if (hasSlottedButtons || this.showDefaultButtons) {
571
- return;
572
- }
573
- this.confirm();
574
- };
575
937
  get isCalendarPicker() {
576
938
  const { presentation } = this;
577
939
  return presentation === 'date' || presentation === 'date-time' || presentation === 'time-date';
578
940
  }
579
- initializeKeyboardListeners = () => {
580
- const calendarBodyRef = this.calendarBodyRef;
581
- if (!calendarBodyRef) {
582
- return;
583
- }
584
- const root = this.el.shadowRoot;
585
- /**
586
- * Get a reference to the month
587
- * element we are currently viewing.
588
- */
589
- const currentMonth = calendarBodyRef.querySelector('.calendar-month:nth-of-type(2)');
590
- /**
591
- * When focusing the calendar body, we want to pass focus
592
- * to the working day, but other days should
593
- * only be accessible using the arrow keys. Pressing
594
- * Tab should jump between bodies of selectable content.
595
- */
596
- const checkCalendarBodyFocus = (ev) => {
597
- const record = ev[0];
598
- /**
599
- * If calendar body was already focused
600
- * when this fired or if the calendar body
601
- * if not currently focused, we should not re-focus
602
- * the inner day.
603
- */
604
- if (record.oldValue?.includes('ion-focused') || !calendarBodyRef.classList.contains('ion-focused')) {
605
- return;
606
- }
607
- this.focusWorkingDay(currentMonth);
608
- };
609
- const mo = new MutationObserver(checkCalendarBodyFocus);
610
- mo.observe(calendarBodyRef, { attributeFilter: ['class'], attributeOldValue: true });
611
- this.destroyKeyboardMO = () => {
612
- mo?.disconnect();
613
- };
614
- /**
615
- * We must use keydown not keyup as we want
616
- * to prevent scrolling when using the arrow keys.
617
- */
618
- calendarBodyRef.addEventListener('keydown', (ev) => {
619
- const activeElement = root.activeElement;
620
- if (!activeElement || !activeElement.classList.contains('calendar-day')) {
621
- return;
622
- }
623
- const parts = getPartsFromCalendarDay(activeElement);
624
- let partsToFocus;
625
- switch (ev.key) {
626
- case 'ArrowDown':
627
- ev.preventDefault();
628
- partsToFocus = getNextWeek(parts);
629
- break;
630
- case 'ArrowUp':
631
- ev.preventDefault();
632
- partsToFocus = getPreviousWeek(parts);
633
- break;
634
- case 'ArrowRight':
635
- ev.preventDefault();
636
- partsToFocus = getNextDay(parts);
637
- break;
638
- case 'ArrowLeft':
639
- ev.preventDefault();
640
- partsToFocus = getPreviousDay(parts);
641
- break;
642
- case 'Home':
643
- ev.preventDefault();
644
- partsToFocus = getStartOfWeek(parts);
645
- break;
646
- case 'End':
647
- ev.preventDefault();
648
- partsToFocus = getEndOfWeek(parts);
649
- break;
650
- case 'PageUp':
651
- ev.preventDefault();
652
- partsToFocus = ev.shiftKey ? getPreviousYear(parts) : getPreviousMonth(parts);
653
- break;
654
- case 'PageDown':
655
- ev.preventDefault();
656
- partsToFocus = ev.shiftKey ? getNextYear(parts) : getNextMonth(parts);
657
- break;
658
- /**
659
- * Do not preventDefault here
660
- * as we do not want to override other
661
- * browser defaults such as pressing Enter/Space
662
- * to select a day.
663
- */
664
- default:
665
- return;
666
- }
667
- /**
668
- * If the day we want to move focus to is
669
- * disabled, do not do anything.
670
- */
671
- if (isDayDisabled(partsToFocus, this.minParts, this.maxParts)) {
672
- return;
673
- }
674
- this.setWorkingParts({
675
- ...this.workingParts,
676
- ...partsToFocus,
677
- });
678
- /**
679
- * Give view a chance to re-render
680
- * then move focus to the new working day
681
- */
682
- requestAnimationFrame(() => this.focusWorkingDay(currentMonth));
683
- });
684
- };
685
- focusWorkingDay = (currentMonth) => {
686
- /**
687
- * Get the number of offset days so
688
- * we know how much to offset our next selector by
689
- * to grab the correct calendar-day element.
690
- */
691
- const { day, month, year } = this.workingParts;
692
- const firstOfMonth = new Date(`${month}/1/${year}`).getDay();
693
- const offset = firstOfMonth >= this.firstDayOfWeek
694
- ? firstOfMonth - this.firstDayOfWeek
695
- : 7 - (this.firstDayOfWeek - firstOfMonth);
696
- if (day === null) {
697
- return;
698
- }
699
- /**
700
- * Get the calendar day element
701
- * and focus it.
702
- */
703
- const dayEl = currentMonth.querySelector(`.calendar-day-wrapper:nth-of-type(${offset + day}) .calendar-day`);
704
- if (dayEl) {
705
- dayEl.focus();
706
- }
707
- };
708
- processMinParts = () => {
709
- const { min, defaultParts } = this;
710
- if (min === undefined) {
711
- this.minParts = undefined;
712
- return;
713
- }
714
- this.minParts = parseMinParts(min, defaultParts);
715
- };
716
- processMaxParts = () => {
717
- const { max, defaultParts } = this;
718
- if (max === undefined) {
719
- this.maxParts = undefined;
720
- return;
721
- }
722
- this.maxParts = parseMaxParts(max, defaultParts);
723
- };
724
- initializeCalendarListener = () => {
725
- const calendarBodyRef = this.calendarBodyRef;
726
- if (!calendarBodyRef) {
727
- return;
728
- }
729
- /**
730
- * For performance reasons, we only render 3
731
- * months at a time: The current month, the previous
732
- * month, and the next month. We have a scroll listener
733
- * on the calendar body to append/prepend new months.
734
- *
735
- * We can do this because Stencil is smart enough to not
736
- * re-create the .calendar-month containers, but rather
737
- * update the content within those containers.
738
- *
739
- * As an added bonus, WebKit has some troubles with
740
- * scroll-snap-stop: always, so not rendering all of
741
- * the months in a row allows us to mostly sidestep
742
- * that issue.
743
- */
744
- const months = calendarBodyRef.querySelectorAll('.calendar-month');
745
- const startMonth = months[0];
746
- const workingMonth = months[1];
747
- const endMonth = months[2];
748
- const mode = getIonMode(this);
749
- const needsiOSRubberBandFix = mode === 'ios' && typeof navigator !== 'undefined' && navigator.maxTouchPoints > 1;
750
- /**
751
- * Before setting up the scroll listener,
752
- * scroll the middle month into view.
753
- * scrollIntoView() will scroll entire page
754
- * if element is not in viewport. Use scrollLeft instead.
755
- */
756
- writeTask(() => {
757
- calendarBodyRef.scrollLeft = startMonth.clientWidth * (isRTL(this.el) ? -1 : 1);
758
- const getChangedMonth = (parts) => {
759
- const box = calendarBodyRef.getBoundingClientRect();
760
- /**
761
- * If the current scroll position is all the way to the left
762
- * then we have scrolled to the previous month.
763
- * Otherwise, assume that we have scrolled to the next
764
- * month. We have a tolerance of 2px to account for
765
- * sub pixel rendering.
766
- *
767
- * Check below the next line ensures that we did not
768
- * swipe and abort (i.e. we swiped but we are still on the current month).
769
- */
770
- const condition = isRTL(this.el) ? calendarBodyRef.scrollLeft >= -2 : calendarBodyRef.scrollLeft <= 2;
771
- const month = condition ? startMonth : endMonth;
772
- /**
773
- * The edge of the month must be lined up with
774
- * the edge of the calendar body in order for
775
- * the component to update. Otherwise, it
776
- * may be the case that the user has paused their
777
- * swipe or the browser has not finished snapping yet.
778
- * Rather than check if the x values are equal,
779
- * we give it a tolerance of 2px to account for
780
- * sub pixel rendering.
781
- */
782
- const monthBox = month.getBoundingClientRect();
783
- if (Math.abs(monthBox.x - box.x) > 2)
784
- return;
785
- /**
786
- * If we're force-rendering a month, assume we've
787
- * scrolled to that and return it.
788
- *
789
- * If forceRenderDate is ever used in a context where the
790
- * forced month is not immediately auto-scrolled to, this
791
- * should be updated to also check whether `month` has the
792
- * same month and year as the forced date.
793
- */
794
- const { forceRenderDate } = this;
795
- if (forceRenderDate !== undefined) {
796
- return { month: forceRenderDate.month, year: forceRenderDate.year, day: forceRenderDate.day };
797
- }
798
- /**
799
- * From here, we can determine if the start
800
- * month or the end month was scrolled into view.
801
- * If no month was changed, then we can return from
802
- * the scroll callback early.
803
- */
804
- if (month === startMonth) {
805
- return getPreviousMonth(parts);
806
- }
807
- else if (month === endMonth) {
808
- return getNextMonth(parts);
809
- }
810
- else {
811
- return;
812
- }
813
- };
814
- const updateActiveMonth = () => {
815
- if (needsiOSRubberBandFix) {
816
- calendarBodyRef.style.removeProperty('pointer-events');
817
- appliediOSRubberBandFix = false;
818
- }
819
- /**
820
- * If the month did not change
821
- * then we can return early.
822
- */
823
- const newDate = getChangedMonth(this.workingParts);
824
- if (!newDate)
825
- return;
826
- const { month, day, year } = newDate;
827
- if (isMonthDisabled({ month, year, day: null }, {
828
- minParts: { ...this.minParts, day: null },
829
- maxParts: { ...this.maxParts, day: null },
830
- })) {
831
- return;
832
- }
833
- /**
834
- * Prevent scrolling for other browsers
835
- * to give the DOM time to update and the container
836
- * time to properly snap.
837
- */
838
- calendarBodyRef.style.setProperty('overflow', 'hidden');
839
- /**
840
- * Use a writeTask here to ensure
841
- * that the state is updated and the
842
- * correct month is scrolled into view
843
- * in the same frame. This is not
844
- * typically a problem on newer devices
845
- * but older/slower device may have a flicker
846
- * if we did not do this.
847
- */
848
- writeTask(() => {
849
- this.setWorkingParts({
850
- ...this.workingParts,
851
- month,
852
- day: day,
853
- year,
854
- });
855
- calendarBodyRef.scrollLeft = workingMonth.clientWidth * (isRTL(this.el) ? -1 : 1);
856
- calendarBodyRef.style.removeProperty('overflow');
857
- if (this.resolveForceDateScrolling) {
858
- this.resolveForceDateScrolling();
859
- }
860
- const activeEl = this.el.shadowRoot.activeElement;
861
- if (activeEl && activeEl.classList.contains('calendar-day')) {
862
- activeEl.closest('.calendar-body')?.focus();
863
- }
864
- });
865
- };
866
- /**
867
- * When the container finishes scrolling we
868
- * need to update the DOM with the selected month.
869
- */
870
- let scrollTimeout;
871
- /**
872
- * We do not want to attempt to set pointer-events
873
- * multiple times within a single swipe gesture as
874
- * that adds unnecessary work to the main thread.
875
- */
876
- let appliediOSRubberBandFix = false;
877
- const scrollCallback = () => {
878
- if (scrollTimeout) {
879
- clearTimeout(scrollTimeout);
880
- }
881
- /**
882
- * On iOS it is possible to quickly rubber band
883
- * the scroll area before the scroll timeout has fired.
884
- * This results in users reaching the end of the scrollable
885
- * container before the DOM has updated.
886
- * By setting `pointer-events: none` we can ensure that
887
- * subsequent swipes do not happen while the container
888
- * is snapping.
889
- */
890
- if (!appliediOSRubberBandFix && needsiOSRubberBandFix) {
891
- calendarBodyRef.style.setProperty('pointer-events', 'none');
892
- appliediOSRubberBandFix = true;
893
- }
894
- // Wait ~3 frames
895
- scrollTimeout = setTimeout(updateActiveMonth, 50);
896
- };
897
- calendarBodyRef.addEventListener('scroll', scrollCallback);
898
- this.destroyCalendarListener = () => {
899
- calendarBodyRef.removeEventListener('scroll', scrollCallback);
900
- };
901
- });
902
- };
903
941
  connectedCallback() {
904
942
  this.clearFocusVisible = startFocusVisible(this.el).destroy;
905
943
  this.loadTimeout = setTimeout(() => {
@@ -913,66 +951,10 @@ export class Datetime {
913
951
  }
914
952
  this.loadTimeoutCleanup();
915
953
  }
916
- /**
917
- * Clean up all listeners except for the overlay
918
- * listener. This is so that we can re-create the listeners
919
- * if the datetime has been hidden/presented by a modal or popover.
920
- */
921
- destroyInteractionListeners = () => {
922
- const { destroyCalendarListener, destroyKeyboardMO } = this;
923
- if (destroyCalendarListener !== undefined) {
924
- destroyCalendarListener();
925
- }
926
- if (destroyKeyboardMO !== undefined) {
927
- destroyKeyboardMO();
928
- }
929
- };
930
954
  initializeListeners() {
931
955
  this.initializeCalendarListener();
932
956
  this.initializeKeyboardListeners();
933
957
  }
934
- /**
935
- * TODO(FW-6931): Remove this fallback upon solving the root cause
936
- * Fallback to ensure the datetime becomes ready even if
937
- * IntersectionObserver never reports it as intersecting.
938
- *
939
- * This is primarily used in environments where the observer
940
- * might not fire as expected, such as when running under
941
- * synthetic tests that stub IntersectionObserver.
942
- */
943
- ensureReadyIfVisible = () => {
944
- if (this.el.classList.contains('datetime-ready')) {
945
- return;
946
- }
947
- const rect = this.el.getBoundingClientRect();
948
- if (rect.width === 0 || rect.height === 0) {
949
- return;
950
- }
951
- this.markReady();
952
- };
953
- markReady = () => {
954
- if (this.el.classList.contains('datetime-ready')) {
955
- return;
956
- }
957
- this.initializeListeners();
958
- /**
959
- * TODO FW-2793: Datetime needs a frame to ensure that it
960
- * can properly scroll contents into view. As a result
961
- * we hide the scrollable content until after that frame
962
- * so users do not see the content quickly shifting. The downside
963
- * is that the content will pop into view a frame after. Maybe there
964
- * is a better way to handle this?
965
- */
966
- writeTask(() => {
967
- this.el.classList.add('datetime-ready');
968
- });
969
- };
970
- loadTimeoutCleanup = () => {
971
- if (this.loadTimeout) {
972
- clearTimeout(this.loadTimeout);
973
- this.loadTimeout = undefined;
974
- }
975
- };
976
958
  componentDidLoad() {
977
959
  const { el, intersectionTrackerRef } = this;
978
960
  /**
@@ -1116,119 +1098,6 @@ export class Datetime {
1116
1098
  this.ionRender.emit();
1117
1099
  });
1118
1100
  }
1119
- processValue = (value) => {
1120
- const hasValue = value !== null && value !== undefined && value !== '' && (!Array.isArray(value) || value.length > 0);
1121
- const valueToProcess = hasValue ? parseDate(value) : this.defaultParts;
1122
- const { minParts, maxParts, workingParts, el } = this;
1123
- this.warnIfIncorrectValueUsage();
1124
- /**
1125
- * Return early if the value wasn't parsed correctly, such as
1126
- * if an improperly formatted date string was provided.
1127
- */
1128
- if (!valueToProcess) {
1129
- return;
1130
- }
1131
- /**
1132
- * Datetime should only warn of out of bounds values
1133
- * if set by the user. If the `value` is undefined,
1134
- * we will default to today's date which may be out
1135
- * of bounds. In this case, the warning makes it look
1136
- * like the developer did something wrong which is
1137
- * not true.
1138
- */
1139
- if (hasValue) {
1140
- warnIfValueOutOfBounds(valueToProcess, minParts, maxParts);
1141
- }
1142
- /**
1143
- * If there are multiple values, clamp to the last one.
1144
- * This is because the last value is the one that the user
1145
- * has most recently interacted with.
1146
- */
1147
- const singleValue = Array.isArray(valueToProcess) ? valueToProcess[valueToProcess.length - 1] : valueToProcess;
1148
- const targetValue = clampDate(singleValue, minParts, maxParts);
1149
- const { month, day, year, hour, minute } = targetValue;
1150
- const ampm = parseAmPm(hour);
1151
- /**
1152
- * Since `activeParts` indicates a value that been explicitly selected
1153
- * either by the user or the app, only update `activeParts` if the
1154
- * `value` property is set.
1155
- */
1156
- if (hasValue) {
1157
- if (Array.isArray(valueToProcess)) {
1158
- this.activeParts = [...valueToProcess];
1159
- }
1160
- else {
1161
- this.activeParts = {
1162
- month,
1163
- day,
1164
- year,
1165
- hour,
1166
- minute,
1167
- ampm,
1168
- };
1169
- }
1170
- }
1171
- else {
1172
- /**
1173
- * Reset the active parts if the value is not set.
1174
- * This will clear the selected calendar day when
1175
- * performing a clear action or using the reset() method.
1176
- */
1177
- this.activeParts = [];
1178
- }
1179
- const didChangeMonth = (month !== undefined && month !== workingParts.month) || (year !== undefined && year !== workingParts.year);
1180
- const bodyIsVisible = el.classList.contains('datetime-ready');
1181
- const { isGridStyle, showMonthAndYear } = this;
1182
- if (isGridStyle && didChangeMonth && bodyIsVisible && !showMonthAndYear) {
1183
- /**
1184
- * Only animate if:
1185
- * 1. We're using grid style (wheel style pickers should just jump to new value)
1186
- * 2. The month and/or year actually changed, and both are defined (otherwise there's nothing to animate to)
1187
- * 3. The calendar body is visible (prevents animation when in collapsed datetime-button, for example)
1188
- * 4. The month/year picker is not open (since you wouldn't see the animation anyway)
1189
- */
1190
- this.animateToDate(targetValue);
1191
- }
1192
- else {
1193
- this.setWorkingParts({
1194
- month,
1195
- day,
1196
- year,
1197
- hour,
1198
- minute,
1199
- ampm,
1200
- });
1201
- }
1202
- };
1203
- animateToDate = async (targetValue) => {
1204
- const { workingParts } = this;
1205
- /**
1206
- * Tell other render functions that we need to force the
1207
- * target month to appear in place of the actual next/prev month.
1208
- * Because this is a State variable, a rerender will be triggered
1209
- * automatically, updating the rendered months.
1210
- */
1211
- this.forceRenderDate = targetValue;
1212
- /**
1213
- * Flag that we've started scrolling to the forced date.
1214
- * The resolve function will be called by the datetime's
1215
- * scroll listener when it's done updating everything.
1216
- * This is a replacement for making prev/nextMonth async,
1217
- * since the logic we're waiting on is in a listener.
1218
- */
1219
- const forceDateScrollingPromise = new Promise((resolve) => {
1220
- this.resolveForceDateScrolling = resolve;
1221
- });
1222
- /**
1223
- * Animate smoothly to the forced month. This will also update
1224
- * workingParts and correct the surrounding months for us.
1225
- */
1226
- const targetMonthIsBefore = isBefore(targetValue, workingParts);
1227
- targetMonthIsBefore ? this.prevMonth() : this.nextMonth();
1228
- await forceDateScrollingPromise;
1229
- this.resolveForceDateScrolling = undefined;
1230
- this.forceRenderDate = undefined;
1231
- };
1232
1101
  componentWillLoad() {
1233
1102
  const { el, formatOptions, highlightedDates, multiple, presentation, preferWheel } = this;
1234
1103
  if (multiple) {
@@ -1279,52 +1148,6 @@ export class Datetime {
1279
1148
  'interactive-disabled': this.disabled,
1280
1149
  });
1281
1150
  }
1282
- onFocus = () => {
1283
- this.ionFocus.emit();
1284
- };
1285
- onBlur = () => {
1286
- this.ionBlur.emit();
1287
- };
1288
- hasValue = () => {
1289
- return this.value != null;
1290
- };
1291
- nextMonth = () => {
1292
- const calendarBodyRef = this.calendarBodyRef;
1293
- if (!calendarBodyRef) {
1294
- return;
1295
- }
1296
- const nextMonth = calendarBodyRef.querySelector('.calendar-month:last-of-type');
1297
- if (!nextMonth) {
1298
- return;
1299
- }
1300
- const left = nextMonth.offsetWidth * 2;
1301
- const scrollMode = config.getBoolean('animated', true) ? 'smooth' : 'instant';
1302
- calendarBodyRef.scrollTo({
1303
- top: 0,
1304
- left: left * (isRTL(this.el) ? -1 : 1),
1305
- behavior: scrollMode,
1306
- });
1307
- };
1308
- prevMonth = () => {
1309
- const calendarBodyRef = this.calendarBodyRef;
1310
- if (!calendarBodyRef) {
1311
- return;
1312
- }
1313
- const prevMonth = calendarBodyRef.querySelector('.calendar-month:first-of-type');
1314
- if (!prevMonth) {
1315
- return;
1316
- }
1317
- const left = prevMonth.offsetWidth * 2;
1318
- const scrollMode = config.getBoolean('animated', true) ? 'smooth' : 'instant';
1319
- calendarBodyRef.scrollTo({
1320
- top: 0,
1321
- left: left * (isRTL(this.el) ? 1 : -1),
1322
- behavior: scrollMode,
1323
- });
1324
- };
1325
- toggleMonthAndYearView = () => {
1326
- this.showMonthAndYear = !this.showMonthAndYear;
1327
- };
1328
1151
  /**
1329
1152
  * Universal render methods
1330
1153
  * These are pieces of datetime that