@sparkle-learning/core 0.0.27 → 0.0.30

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 (697) hide show
  1. package/dist/cjs/{PrivateRoute-cee9b061.js → PrivateRoute-043bb7d3.js} +6 -40
  2. package/dist/cjs/{active-router-3bd7b540.js → active-router-eedb3bfe.js} +1 -1
  3. package/dist/cjs/{animation-05337433.js → animation-6132e37f.js} +28 -4
  4. package/dist/cjs/app-globals-9869bf67.js +9 -0
  5. package/dist/cjs/{auth.store-aba3d22f.js → auth.store-ff3fda09.js} +1869 -357
  6. package/dist/cjs/compass-svg.cjs.entry.js +1 -1
  7. package/dist/cjs/context-consumer.cjs.entry.js +1 -1
  8. package/dist/cjs/course-select.cjs.entry.js +1 -1
  9. package/dist/cjs/{cubic-bezier-24e309bf.js → cubic-bezier-293f4663.js} +3 -0
  10. package/dist/cjs/dir-5af5259a.js +20 -0
  11. package/dist/cjs/{facilitator.service-e1e2f719.js → facilitator.service-faac5c0c.js} +1 -1
  12. package/dist/cjs/feed.service-66405969.js +124 -0
  13. package/dist/cjs/focus-visible-ad3828a7.js +63 -0
  14. package/dist/cjs/framework-delegate-2470a246.js +113 -0
  15. package/dist/cjs/{gesture-controller-e824cfb3.js → gesture-controller-07c31f70.js} +3 -0
  16. package/dist/cjs/{haptic-415dac5b.js → haptic-91e86eb7.js} +3 -0
  17. package/dist/cjs/{hardware-back-button-ca468aae.js → hardware-back-button-f7b5d99e.js} +3 -0
  18. package/dist/cjs/header-mobile-collapse_61.cjs.entry.js +18001 -0
  19. package/dist/cjs/{helpers-26770c32.js → helpers-7e28976c.js} +122 -3
  20. package/dist/cjs/{icons-a0fef92b.js → icons-b8a2231a.js} +1 -1
  21. package/dist/cjs/{index-427d03fb.js → index-185f9c5a.js} +3 -0
  22. package/dist/cjs/{index-6eff209d.js → index-43642662.js} +24 -3
  23. package/dist/cjs/{index-7bcd36a0.js → index-459a5fa9.js} +20 -4
  24. package/dist/cjs/index-8540d72e.js +42 -0
  25. package/dist/cjs/{index-58b3ee93.js → index-b12edb26.js} +34 -5
  26. package/dist/cjs/{index-fbf4d3bf.js → index-bae2a754.js} +303 -207
  27. package/dist/cjs/index.cjs.js +8 -7
  28. package/dist/cjs/index.es-ef3efdfb.js +10671 -0
  29. package/dist/cjs/{input-shims-213e83f8.js → input-shims-6c442c9f.js} +34 -10
  30. package/dist/cjs/ion-accordion-group.cjs.entry.js +197 -0
  31. package/dist/cjs/ion-accordion.cjs.entry.js +340 -0
  32. package/dist/cjs/ion-action-sheet_4.cjs.entry.js +2203 -0
  33. package/dist/cjs/ion-app.cjs.entry.js +23 -8
  34. package/dist/cjs/ion-back-button.cjs.entry.js +14 -9
  35. package/dist/cjs/ion-backdrop.cjs.entry.js +3 -3
  36. package/dist/cjs/ion-badge.cjs.entry.js +3 -3
  37. package/dist/cjs/ion-breadcrumb.cjs.entry.js +103 -0
  38. package/dist/cjs/ion-breadcrumbs.cjs.entry.js +135 -0
  39. package/dist/cjs/ion-buttons_3.cjs.entry.js +7 -6
  40. package/dist/cjs/ion-card-header.cjs.entry.js +3 -3
  41. package/dist/cjs/ion-card-subtitle.cjs.entry.js +3 -3
  42. package/dist/cjs/ion-card-title.cjs.entry.js +3 -3
  43. package/dist/cjs/ion-chip.cjs.entry.js +3 -3
  44. package/dist/cjs/ion-content_2.cjs.entry.js +144 -56
  45. package/dist/cjs/ion-datetime.cjs.entry.js +1902 -779
  46. package/dist/cjs/ion-fab-button.cjs.entry.js +5 -4
  47. package/dist/cjs/ion-fab-list.cjs.entry.js +2 -2
  48. package/dist/cjs/ion-fab.cjs.entry.js +2 -2
  49. package/dist/cjs/ion-footer.cjs.entry.js +79 -4
  50. package/dist/cjs/ion-img.cjs.entry.js +33 -7
  51. package/dist/cjs/ion-infinite-scroll-content.cjs.entry.js +3 -3
  52. package/dist/cjs/ion-infinite-scroll.cjs.entry.js +4 -2
  53. package/dist/cjs/ion-item-divider.cjs.entry.js +3 -3
  54. package/dist/cjs/ion-item-group.cjs.entry.js +2 -2
  55. package/dist/cjs/ion-item-option.cjs.entry.js +4 -4
  56. package/dist/cjs/ion-item-options.cjs.entry.js +3 -3
  57. package/dist/cjs/ion-item-sliding.cjs.entry.js +52 -8
  58. package/dist/cjs/ion-loading.cjs.entry.js +23 -11
  59. package/dist/cjs/ion-menu-button.cjs.entry.js +17 -11
  60. package/dist/cjs/ion-menu-toggle.cjs.entry.js +7 -7
  61. package/dist/cjs/ion-menu.cjs.entry.js +141 -29
  62. package/dist/cjs/ion-modal.cjs.entry.js +649 -75
  63. package/dist/cjs/ion-nav-link.cjs.entry.js +4 -1
  64. package/dist/cjs/ion-nav.cjs.entry.js +140 -137
  65. package/dist/cjs/ion-picker-column-internal_2.cjs.entry.js +700 -0
  66. package/dist/cjs/ion-picker-column.cjs.entry.js +5 -5
  67. package/dist/cjs/ion-picker.cjs.entry.js +18 -11
  68. package/dist/cjs/ion-progress-bar.cjs.entry.js +17 -13
  69. package/dist/cjs/ion-refresher-content.cjs.entry.js +7 -6
  70. package/dist/cjs/ion-refresher.cjs.entry.js +83 -84
  71. package/dist/cjs/ion-reorder-group.cjs.entry.js +9 -8
  72. package/dist/cjs/ion-reorder.cjs.entry.js +5 -4
  73. package/dist/cjs/ion-route-redirect.cjs.entry.js +1 -1
  74. package/dist/cjs/ion-route.cjs.entry.js +1 -1
  75. package/dist/cjs/ion-router-link.cjs.entry.js +3 -3
  76. package/dist/cjs/ion-router-outlet.cjs.entry.js +50 -12
  77. package/dist/cjs/ion-router.cjs.entry.js +378 -234
  78. package/dist/cjs/ion-searchbar.cjs.entry.js +50 -17
  79. package/dist/cjs/ion-segment-button.cjs.entry.js +12 -9
  80. package/dist/cjs/ion-segment.cjs.entry.js +89 -10
  81. package/dist/cjs/ion-select_2.cjs.entry.js +64 -30
  82. package/dist/cjs/ion-skeleton-text.cjs.entry.js +4 -4
  83. package/dist/cjs/ion-slide.cjs.entry.js +2 -2
  84. package/dist/cjs/ion-slides.cjs.entry.js +19 -32
  85. package/dist/cjs/ion-split-pane.cjs.entry.js +8 -3
  86. package/dist/cjs/ion-tab-bar.cjs.entry.js +25 -12
  87. package/dist/cjs/ion-tab-button.cjs.entry.js +2 -2
  88. package/dist/cjs/ion-tab.cjs.entry.js +3 -2
  89. package/dist/cjs/ion-tabs.cjs.entry.js +1 -1
  90. package/dist/cjs/ion-textarea.cjs.entry.js +9 -8
  91. package/dist/cjs/ion-thumbnail.cjs.entry.js +2 -2
  92. package/dist/cjs/ion-toast.cjs.entry.js +37 -27
  93. package/dist/cjs/ion-toggle.cjs.entry.js +15 -15
  94. package/dist/cjs/ion-virtual-scroll.cjs.entry.js +13 -3
  95. package/dist/cjs/{ionic-global-4930d319.js → ionic-global-878073d1.js} +103 -77
  96. package/dist/cjs/{ios.transition-6e1fd3d6.js → ios.transition-c3bfb096.js} +8 -5
  97. package/dist/cjs/{keyboard-1dcbde6c.js → keyboard-dfd76ac3.js} +3 -0
  98. package/dist/cjs/loader.cjs.js +5 -5
  99. package/dist/cjs/localstorage.service-6346a41d.js +40 -0
  100. package/dist/cjs/{md.transition-3652ad78.js → md.transition-7eb9a1a7.js} +7 -4
  101. package/dist/cjs/{menu-toggle-util-a8fb4c56.js → menu-toggle-util-cb549c2c.js} +4 -1
  102. package/dist/cjs/{overlays-08a817ea.js → overlays-0a748609.js} +188 -47
  103. package/dist/cjs/{purify-596fc2d6.js → purify-d0ad2883.js} +187 -74
  104. package/dist/cjs/sparkle-animation-player.cjs.entry.js +56 -50
  105. package/dist/cjs/sparkle-character-intro.cjs.entry.js +26 -0
  106. package/dist/cjs/sparkle-code.cjs.entry.js +2 -2
  107. package/dist/cjs/sparkle-compass-post.cjs.entry.js +1 -1
  108. package/dist/cjs/sparkle-compass.cjs.entry.js +1 -1
  109. package/dist/cjs/sparkle-core.cjs.js +7 -7
  110. package/dist/cjs/sparkle-emoji.cjs.entry.js +1 -1
  111. package/dist/cjs/sparkle-facilitator-notes-form.cjs.entry.js +7 -7
  112. package/dist/cjs/sparkle-feed-post.cjs.entry.js +1 -1
  113. package/dist/cjs/sparkle-feedback.cjs.entry.js +7 -7
  114. package/dist/cjs/sparkle-goal-form.cjs.entry.js +15 -14
  115. package/dist/cjs/sparkle-gww-comment-list.cjs.entry.js +1 -1
  116. package/dist/cjs/sparkle-gww-graph.cjs.entry.js +1 -1
  117. package/dist/cjs/sparkle-lower-content-nav.cjs.entry.js +1 -1
  118. package/dist/cjs/sparkle-menu-collapsible.cjs.entry.js +2 -2
  119. package/dist/cjs/sparkle-modal-image.cjs.entry.js +1 -1
  120. package/dist/cjs/sparkle-notfound-page.cjs.entry.js +1 -1
  121. package/dist/cjs/sparkle-overlay.cjs.entry.js +1 -1
  122. package/dist/cjs/sparkle-poll.cjs.entry.js +1 -1
  123. package/dist/cjs/sparkle-quiz-container.cjs.entry.js +1 -1
  124. package/dist/cjs/sparkle-quiz-feedback_5.cjs.entry.js +1 -1
  125. package/dist/cjs/sparkle-quiz.cjs.entry.js +2 -2
  126. package/dist/cjs/sparkle-select.cjs.entry.js +1 -1
  127. package/dist/cjs/sparkle-sidebar.cjs.entry.js +1 -1
  128. package/dist/cjs/sparkle-tab.cjs.entry.js +1 -1
  129. package/dist/cjs/sparkle-table-of-contents.cjs.entry.js +1 -1
  130. package/dist/cjs/sparkle-tabs.cjs.entry.js +1 -1
  131. package/dist/cjs/sparkle-youtube.cjs.entry.js +2 -2
  132. package/dist/cjs/{spinner-configs-559523fd.js → spinner-configs-6f6b7ef0.js} +36 -1
  133. package/dist/cjs/status-tap-8697433c.js +40 -0
  134. package/dist/cjs/stencil-async-content.cjs.entry.js +1 -1
  135. package/dist/cjs/stencil-route-title.cjs.entry.js +2 -2
  136. package/dist/cjs/stencil-router-prompt.cjs.entry.js +2 -2
  137. package/dist/cjs/{student.service-41c7c78d.js → student.service-744c3155.js} +1 -1
  138. package/dist/cjs/{swipe-back-c1951cbd.js → swipe-back-7e08b5e0.js} +32 -8
  139. package/dist/cjs/{swiper.bundle-cbea42d8.js → swiper.bundle-8c897c07.js} +4 -4
  140. package/dist/cjs/{tap-click-cd858b48.js → tap-click-1caf1780.js} +8 -1
  141. package/dist/cjs/{theme-98ccfc24.js → theme-4252ac15.js} +3 -0
  142. package/dist/cjs/util-d383acb8.js +2462 -0
  143. package/dist/collection/collection-manifest.json +9 -2
  144. package/dist/collection/components/layout/page/page.js +1 -0
  145. package/dist/collection/components/sparkle-animation-player/sparkle-animation-player.js +78 -66
  146. package/dist/collection/components/sparkle-character-intro/assets/characters/character-img.jpg +0 -0
  147. package/dist/collection/components/sparkle-character-intro/assets/characters/jen.png +0 -0
  148. package/dist/collection/components/sparkle-character-intro/assets/characters/kimberly.png +0 -0
  149. package/dist/collection/components/sparkle-character-intro/assets/characters/valeria.png +0 -0
  150. package/dist/collection/components/sparkle-character-intro/assets/characters/yuna.png +0 -0
  151. package/dist/collection/components/sparkle-character-intro/assets/characters/zynab.png +0 -0
  152. package/dist/collection/components/sparkle-character-intro/sparkle-character-intro.css +67 -0
  153. package/dist/collection/components/sparkle-character-intro/sparkle-character-intro.js +64 -0
  154. package/dist/collection/components/sparkle-course-root/sparkle-course-root.js +48 -43
  155. package/dist/collection/components/sparkle-youtube/sparkle-youtube.js +6 -2
  156. package/dist/collection/util.js +1 -0
  157. package/dist/esm/{PrivateRoute-9f0973bb.js → PrivateRoute-b9937c45.js} +3 -37
  158. package/dist/esm/{active-router-b3ae32c7.js → active-router-909088d6.js} +1 -1
  159. package/dist/esm/{animation-72fdacfb.js → animation-b306f6c2.js} +28 -4
  160. package/dist/esm/app-globals-5c736ae5.js +7 -0
  161. package/dist/esm/auth.store-3ed2389e.js +4061 -0
  162. package/dist/esm/compass-svg.entry.js +1 -1
  163. package/dist/esm/context-consumer.entry.js +1 -1
  164. package/dist/esm/course-select.entry.js +1 -1
  165. package/dist/esm/{cubic-bezier-ed243a9b.js → cubic-bezier-a7ad9c8e.js} +3 -0
  166. package/dist/esm/dir-03012648.js +18 -0
  167. package/dist/esm/{facilitator.service-cddb2feb.js → facilitator.service-ec0a9739.js} +1 -1
  168. package/dist/esm/feed.service-33b83cb7.js +119 -0
  169. package/dist/esm/focus-visible-40cda868.js +61 -0
  170. package/dist/esm/framework-delegate-3bc58c27.js +109 -0
  171. package/dist/esm/{gesture-controller-604336b7.js → gesture-controller-686622ba.js} +3 -0
  172. package/dist/esm/{haptic-67928174.js → haptic-99c9e346.js} +4 -1
  173. package/dist/esm/{hardware-back-button-508e48cf.js → hardware-back-button-b6ccf74a.js} +3 -0
  174. package/dist/esm/header-mobile-collapse_61.entry.js +17937 -0
  175. package/dist/esm/{helpers-e7f66b2b.js → helpers-39367fe1.js} +119 -4
  176. package/dist/esm/{icons-33e5804c.js → icons-5debfbaf.js} +1 -1
  177. package/dist/esm/{index-cc97b114.js → index-435af8e6.js} +3 -0
  178. package/dist/esm/{index-55fc9f5e.js → index-5568e3fa.js} +303 -208
  179. package/dist/esm/{index-dc09784f.js → index-9594837e.js} +20 -4
  180. package/dist/esm/{index-b2ad0f1a.js → index-a12c14bd.js} +25 -4
  181. package/dist/esm/{index-a94619f9.js → index-c26d8655.js} +34 -5
  182. package/dist/esm/index-dc61f152.js +22 -0
  183. package/dist/esm/index.es-97dd8174.js +10585 -0
  184. package/dist/esm/index.js +8 -7
  185. package/dist/esm/{input-shims-3a97fa86.js → input-shims-cc98ea92.js} +34 -10
  186. package/dist/esm/ion-accordion-group.entry.js +193 -0
  187. package/dist/esm/ion-accordion.entry.js +336 -0
  188. package/dist/esm/ion-action-sheet_4.entry.js +2196 -0
  189. package/dist/esm/ion-app.entry.js +23 -8
  190. package/dist/esm/ion-back-button.entry.js +14 -9
  191. package/dist/esm/ion-backdrop.entry.js +3 -3
  192. package/dist/esm/ion-badge.entry.js +3 -3
  193. package/dist/esm/ion-breadcrumb.entry.js +99 -0
  194. package/dist/esm/ion-breadcrumbs.entry.js +131 -0
  195. package/dist/esm/ion-buttons_3.entry.js +7 -6
  196. package/dist/esm/ion-card-header.entry.js +3 -3
  197. package/dist/esm/ion-card-subtitle.entry.js +3 -3
  198. package/dist/esm/ion-card-title.entry.js +3 -3
  199. package/dist/esm/ion-chip.entry.js +3 -3
  200. package/dist/esm/ion-content_2.entry.js +144 -56
  201. package/dist/esm/ion-datetime.entry.js +1902 -779
  202. package/dist/esm/ion-fab-button.entry.js +5 -4
  203. package/dist/esm/ion-fab-list.entry.js +2 -2
  204. package/dist/esm/ion-fab.entry.js +2 -2
  205. package/dist/esm/ion-footer.entry.js +79 -4
  206. package/dist/esm/ion-img.entry.js +33 -7
  207. package/dist/esm/ion-infinite-scroll-content.entry.js +3 -3
  208. package/dist/esm/ion-infinite-scroll.entry.js +4 -2
  209. package/dist/esm/ion-item-divider.entry.js +3 -3
  210. package/dist/esm/ion-item-group.entry.js +2 -2
  211. package/dist/esm/ion-item-option.entry.js +4 -4
  212. package/dist/esm/ion-item-options.entry.js +3 -3
  213. package/dist/esm/ion-item-sliding.entry.js +52 -8
  214. package/dist/esm/ion-loading.entry.js +23 -11
  215. package/dist/esm/ion-menu-button.entry.js +17 -11
  216. package/dist/esm/ion-menu-toggle.entry.js +7 -7
  217. package/dist/esm/ion-menu.entry.js +141 -29
  218. package/dist/esm/ion-modal.entry.js +649 -75
  219. package/dist/esm/ion-nav-link.entry.js +4 -1
  220. package/dist/esm/ion-nav.entry.js +140 -137
  221. package/dist/esm/ion-picker-column-internal_2.entry.js +695 -0
  222. package/dist/esm/ion-picker-column.entry.js +5 -5
  223. package/dist/esm/ion-picker.entry.js +18 -11
  224. package/dist/esm/ion-progress-bar.entry.js +17 -13
  225. package/dist/esm/ion-refresher-content.entry.js +7 -6
  226. package/dist/esm/ion-refresher.entry.js +82 -83
  227. package/dist/esm/ion-reorder-group.entry.js +9 -8
  228. package/dist/esm/ion-reorder.entry.js +5 -4
  229. package/dist/esm/ion-route-redirect.entry.js +1 -1
  230. package/dist/esm/ion-route.entry.js +1 -1
  231. package/dist/esm/ion-router-link.entry.js +3 -3
  232. package/dist/esm/ion-router-outlet.entry.js +50 -12
  233. package/dist/esm/ion-router.entry.js +378 -234
  234. package/dist/esm/ion-searchbar.entry.js +50 -17
  235. package/dist/esm/ion-segment-button.entry.js +12 -9
  236. package/dist/esm/ion-segment.entry.js +89 -10
  237. package/dist/esm/ion-select_2.entry.js +64 -30
  238. package/dist/esm/ion-skeleton-text.entry.js +4 -4
  239. package/dist/esm/ion-slide.entry.js +2 -2
  240. package/dist/esm/ion-slides.entry.js +19 -32
  241. package/dist/esm/ion-split-pane.entry.js +8 -3
  242. package/dist/esm/ion-tab-bar.entry.js +25 -12
  243. package/dist/esm/ion-tab-button.entry.js +2 -2
  244. package/dist/esm/ion-tab.entry.js +3 -2
  245. package/dist/esm/ion-tabs.entry.js +1 -1
  246. package/dist/esm/ion-textarea.entry.js +9 -8
  247. package/dist/esm/ion-thumbnail.entry.js +2 -2
  248. package/dist/esm/ion-toast.entry.js +37 -27
  249. package/dist/esm/ion-toggle.entry.js +15 -15
  250. package/dist/esm/ion-virtual-scroll.entry.js +13 -3
  251. package/dist/esm/{ionic-global-1f9287cc.js → ionic-global-0939c477.js} +103 -77
  252. package/dist/esm/{ios.transition-d01abefd.js → ios.transition-b4ca8a33.js} +8 -5
  253. package/dist/esm/{keyboard-06906eac.js → keyboard-2503e874.js} +3 -0
  254. package/dist/esm/loader.js +5 -5
  255. package/dist/esm/localstorage.service-4bf408c8.js +36 -0
  256. package/dist/esm/{md.transition-245ffa55.js → md.transition-ca5e0322.js} +7 -4
  257. package/dist/esm/{menu-toggle-util-fe83fcf5.js → menu-toggle-util-7fa22c2f.js} +4 -1
  258. package/dist/esm/{overlays-8363621c.js → overlays-34cfa9e0.js} +187 -47
  259. package/dist/esm/polyfills/css-shim.js +1 -1
  260. package/dist/esm/polyfills/index.js +2 -2
  261. package/dist/esm/{purify-4247e2d0.js → purify-ffce2b4c.js} +185 -72
  262. package/dist/esm/sparkle-animation-player.entry.js +56 -50
  263. package/dist/esm/sparkle-character-intro.entry.js +22 -0
  264. package/dist/esm/sparkle-code.entry.js +2 -2
  265. package/dist/esm/sparkle-compass-post.entry.js +1 -1
  266. package/dist/esm/sparkle-compass.entry.js +1 -1
  267. package/dist/esm/sparkle-core.js +7 -7
  268. package/dist/esm/sparkle-emoji.entry.js +1 -1
  269. package/dist/esm/sparkle-facilitator-notes-form.entry.js +7 -7
  270. package/dist/esm/sparkle-feed-post.entry.js +1 -1
  271. package/dist/esm/sparkle-feedback.entry.js +7 -7
  272. package/dist/esm/sparkle-goal-form.entry.js +8 -7
  273. package/dist/esm/sparkle-gww-comment-list.entry.js +1 -1
  274. package/dist/esm/sparkle-gww-graph.entry.js +1 -1
  275. package/dist/esm/sparkle-lower-content-nav.entry.js +1 -1
  276. package/dist/esm/sparkle-menu-collapsible.entry.js +2 -2
  277. package/dist/esm/sparkle-modal-image.entry.js +1 -1
  278. package/dist/esm/sparkle-notfound-page.entry.js +1 -1
  279. package/dist/esm/sparkle-overlay.entry.js +1 -1
  280. package/dist/esm/sparkle-poll.entry.js +1 -1
  281. package/dist/esm/sparkle-quiz-container.entry.js +1 -1
  282. package/dist/esm/sparkle-quiz-feedback_5.entry.js +1 -1
  283. package/dist/esm/sparkle-quiz.entry.js +2 -2
  284. package/dist/esm/sparkle-select.entry.js +1 -1
  285. package/dist/esm/sparkle-sidebar.entry.js +1 -1
  286. package/dist/esm/sparkle-tab.entry.js +1 -1
  287. package/dist/esm/sparkle-table-of-contents.entry.js +1 -1
  288. package/dist/esm/sparkle-tabs.entry.js +1 -1
  289. package/dist/esm/sparkle-youtube.entry.js +2 -2
  290. package/dist/esm/{spinner-configs-9536fae2.js → spinner-configs-f609a655.js} +36 -1
  291. package/dist/esm/status-tap-6351a0cb.js +38 -0
  292. package/dist/esm/stencil-async-content.entry.js +1 -1
  293. package/dist/esm/stencil-route-title.entry.js +2 -2
  294. package/dist/esm/stencil-router-prompt.entry.js +2 -2
  295. package/dist/esm/{student.service-c36c5a75.js → student.service-29b688ba.js} +1 -1
  296. package/dist/esm/{swipe-back-21f58ecf.js → swipe-back-34251834.js} +32 -8
  297. package/dist/esm/{swiper.bundle-d4422d52.js → swiper.bundle-b6a959de.js} +4 -4
  298. package/dist/esm/{tap-click-8c728329.js → tap-click-13f1fb0d.js} +8 -1
  299. package/dist/esm/{theme-12606872.js → theme-c336c9d9.js} +3 -0
  300. package/dist/esm/util-6ef753e9.js +2451 -0
  301. package/dist/loader/index.d.ts +0 -1
  302. package/dist/node_modules/@ionic/core/dist/collection/components/accordion/accordion.ios.css +75 -0
  303. package/dist/node_modules/@ionic/core/dist/collection/components/accordion/accordion.md.css +72 -0
  304. package/dist/node_modules/@ionic/core/dist/collection/components/accordion-group/accordion-group.ios.css +25 -0
  305. package/dist/node_modules/@ionic/core/dist/collection/components/accordion-group/accordion-group.md.css +59 -0
  306. package/dist/node_modules/@ionic/core/dist/collection/components/action-sheet/action-sheet.ios.css +10 -19
  307. package/dist/node_modules/@ionic/core/dist/collection/components/action-sheet/action-sheet.md.css +19 -16
  308. package/dist/node_modules/@ionic/core/dist/collection/components/alert/alert.md.css +2 -2
  309. package/dist/node_modules/@ionic/core/dist/collection/components/back-button/back-button.ios.css +4 -0
  310. package/dist/node_modules/@ionic/core/dist/collection/components/back-button/back-button.md.css +4 -0
  311. package/dist/node_modules/@ionic/core/dist/collection/components/breadcrumb/breadcrumb.ios.css +234 -0
  312. package/dist/node_modules/@ionic/core/dist/collection/components/breadcrumb/breadcrumb.md.css +237 -0
  313. package/dist/node_modules/@ionic/core/dist/collection/components/breadcrumbs/breadcrumbs.ios.css +38 -0
  314. package/dist/node_modules/@ionic/core/dist/collection/components/breadcrumbs/breadcrumbs.md.css +37 -0
  315. package/dist/node_modules/@ionic/core/dist/collection/components/button/button.ios.css +0 -1
  316. package/dist/node_modules/@ionic/core/dist/collection/components/button/button.md.css +5 -5
  317. package/dist/node_modules/@ionic/core/dist/collection/components/content/content.css +60 -14
  318. package/dist/node_modules/@ionic/core/dist/collection/components/datetime/datetime.ios.css +586 -68
  319. package/dist/node_modules/@ionic/core/dist/collection/components/datetime/datetime.md.css +575 -68
  320. package/dist/node_modules/@ionic/core/dist/collection/components/footer/footer.ios.css +4 -0
  321. package/dist/node_modules/@ionic/core/dist/collection/components/header/header.ios.css +16 -0
  322. package/dist/node_modules/@ionic/core/dist/collection/components/input/input.ios.css +9 -0
  323. package/dist/node_modules/@ionic/core/dist/collection/components/input/input.md.css +9 -0
  324. package/dist/node_modules/@ionic/core/dist/collection/components/item/item.ios.css +105 -17
  325. package/dist/node_modules/@ionic/core/dist/collection/components/item/item.md.css +295 -22
  326. package/dist/node_modules/@ionic/core/dist/collection/components/item-options/item-options.ios.css +6 -6
  327. package/dist/node_modules/@ionic/core/dist/collection/components/item-options/item-options.md.css +6 -6
  328. package/dist/node_modules/@ionic/core/dist/collection/components/item-sliding/item-sliding.css +2 -2
  329. package/dist/node_modules/@ionic/core/dist/collection/components/label/label.ios.css +7 -3
  330. package/dist/node_modules/@ionic/core/dist/collection/components/label/label.md.css +100 -18
  331. package/dist/node_modules/@ionic/core/dist/collection/components/list/list.ios.css +1 -1
  332. package/dist/node_modules/@ionic/core/dist/collection/components/menu/menu.ios.css +2 -2
  333. package/dist/node_modules/@ionic/core/dist/collection/components/menu/menu.md.css +2 -2
  334. package/dist/node_modules/@ionic/core/dist/collection/components/modal/modal.ios.css +74 -11
  335. package/dist/node_modules/@ionic/core/dist/collection/components/modal/modal.md.css +48 -4
  336. package/dist/node_modules/@ionic/core/dist/collection/components/picker-column-internal/picker-column-internal.ios.css +59 -0
  337. package/dist/node_modules/@ionic/core/dist/collection/components/picker-column-internal/picker-column-internal.md.css +62 -0
  338. package/dist/node_modules/@ionic/core/dist/collection/components/picker-internal/picker-internal.ios.css +122 -0
  339. package/dist/node_modules/@ionic/core/dist/collection/components/picker-internal/picker-internal.md.css +118 -0
  340. package/dist/node_modules/@ionic/core/dist/collection/components/popover/popover.ios.css +83 -0
  341. package/dist/node_modules/@ionic/core/dist/collection/components/popover/popover.md.css +49 -0
  342. package/dist/node_modules/@ionic/core/dist/collection/components/progress-bar/progress-bar.ios.css +53 -38
  343. package/dist/node_modules/@ionic/core/dist/collection/components/progress-bar/progress-bar.md.css +53 -38
  344. package/dist/node_modules/@ionic/core/dist/collection/components/range/range.ios.css +3 -3
  345. package/dist/node_modules/@ionic/core/dist/collection/components/range/range.md.css +5 -5
  346. package/dist/node_modules/@ionic/core/dist/collection/components/refresher/refresher.ios.css +12 -0
  347. package/dist/node_modules/@ionic/core/dist/collection/components/refresher/refresher.md.css +2 -2
  348. package/dist/node_modules/@ionic/core/dist/collection/components/searchbar/searchbar.ios.css +1 -1
  349. package/dist/node_modules/@ionic/core/dist/collection/components/searchbar/searchbar.md.css +1 -1
  350. package/dist/node_modules/@ionic/core/dist/collection/components/segment-button/segment-button.ios.css +4 -0
  351. package/dist/node_modules/@ionic/core/dist/collection/components/segment-button/segment-button.md.css +4 -0
  352. package/dist/node_modules/@ionic/core/dist/collection/components/select/select.ios.css +1 -1
  353. package/dist/node_modules/@ionic/core/dist/collection/components/select/select.md.css +30 -2
  354. package/dist/node_modules/@ionic/core/dist/collection/components/select-popover/{select-popover.css → select-popover.ios.css} +4 -4
  355. package/dist/node_modules/@ionic/core/dist/collection/components/select-popover/select-popover.md.css +37 -0
  356. package/dist/node_modules/@ionic/core/dist/collection/components/skeleton-text/skeleton-text.css +4 -4
  357. package/dist/node_modules/@ionic/core/dist/collection/components/spinner/spinner.css +15 -2
  358. package/dist/node_modules/@ionic/core/dist/collection/components/tab-bar/tab-bar.ios.css +2 -1
  359. package/dist/node_modules/@ionic/core/dist/collection/components/tab-bar/tab-bar.md.css +1 -0
  360. package/dist/node_modules/@ionic/core/dist/collection/components/textarea/textarea.ios.css +9 -0
  361. package/dist/node_modules/@ionic/core/dist/collection/components/textarea/textarea.md.css +9 -0
  362. package/dist/node_modules/@ionic/core/dist/collection/components/title/title.ios.css +4 -3
  363. package/dist/node_modules/@ionic/core/dist/collection/components/toast/toast.ios.css +14 -2
  364. package/dist/node_modules/@ionic/core/dist/collection/components/toast/toast.md.css +14 -2
  365. package/dist/node_modules/@ionic/core/dist/collection/components/toggle/toggle.ios.css +1 -0
  366. package/dist/node_modules/@ionic/core/dist/collection/components/toggle/toggle.md.css +1 -0
  367. package/dist/node_modules/@ionic/core/dist/collection/components/toolbar/toolbar.ios.css +3 -2
  368. package/dist/node_modules/@ionic/core/dist/collection/components/toolbar/toolbar.md.css +2 -1
  369. package/dist/node_modules/@ionic/core/dist/collection/components/virtual-scroll/virtual-scroll.css +1 -1
  370. package/dist/node_modules/@sparkle-learning/components/dist/collection/components/button/button.css +49 -0
  371. package/dist/node_modules/@sparkle-learning/components/dist/collection/components/cards/card/card.css +208 -0
  372. package/dist/node_modules/@sparkle-learning/components/dist/collection/components/cards/cards.css +31 -0
  373. package/dist/node_modules/@sparkle-learning/components/dist/collection/components/code/code.css +245 -0
  374. package/dist/node_modules/@sparkle-learning/components/dist/collection/components/dropdown/dropdown.css +115 -0
  375. package/dist/node_modules/@sparkle-learning/components/dist/collection/components/header/header-mobile-collapse/header-mobile-collapse.css +255 -0
  376. package/dist/node_modules/@sparkle-learning/components/dist/collection/components/header/header.css +232 -0
  377. package/dist/node_modules/@sparkle-learning/components/dist/collection/components/menu/collapsible/collapsible.css +3 -0
  378. package/dist/node_modules/@sparkle-learning/components/dist/collection/components/menu/menu-toggle/menu-toggle.css +25 -0
  379. package/dist/node_modules/@sparkle-learning/components/dist/collection/components/menu/menu.css +71 -0
  380. package/dist/node_modules/@sparkle-learning/components/dist/collection/components/nav/nav.css +194 -0
  381. package/dist/node_modules/@sparkle-learning/components/dist/collection/components/notfound-page/notfound-page.css +4 -0
  382. package/dist/node_modules/@sparkle-learning/components/dist/collection/components/overlay/overlay.css +67 -0
  383. package/dist/node_modules/@sparkle-learning/components/dist/collection/components/page-footer/page-footer.css +18 -0
  384. package/dist/node_modules/@sparkle-learning/components/dist/collection/components/pagination/pagination.css +89 -0
  385. package/dist/node_modules/@sparkle-learning/components/dist/collection/components/select/select.css +52 -0
  386. package/dist/node_modules/@sparkle-learning/components/dist/collection/components/sidebar/sidebar.css +98 -0
  387. package/dist/node_modules/@sparkle-learning/components/dist/collection/components/sparkle-lower-content-nav/sparkle-lower-content-nav.css +8 -0
  388. package/dist/node_modules/@sparkle-learning/components/dist/collection/components/table-of-contents/table-of-contents.css +37 -0
  389. package/dist/node_modules/@sparkle-learning/components/dist/collection/components/tabs/tabs.css +64 -0
  390. package/dist/sparkle-core/assets/characters/character-img.jpg +0 -0
  391. package/dist/sparkle-core/assets/characters/jen.png +0 -0
  392. package/dist/sparkle-core/assets/characters/kimberly.png +0 -0
  393. package/dist/sparkle-core/assets/characters/valeria.png +0 -0
  394. package/dist/sparkle-core/assets/characters/yuna.png +0 -0
  395. package/dist/sparkle-core/assets/characters/zynab.png +0 -0
  396. package/dist/sparkle-core/index.esm.js +1 -1
  397. package/dist/sparkle-core/p-0146afa0.entry.js +1 -0
  398. package/dist/sparkle-core/{p-52355989.entry.js → p-016a7aaf.entry.js} +1 -1
  399. package/dist/sparkle-core/p-0187adef.entry.js +1 -0
  400. package/dist/sparkle-core/p-03189863.js +1 -0
  401. package/dist/sparkle-core/{p-d4d9aa4a.entry.js → p-03ec54a8.entry.js} +1 -1
  402. package/dist/sparkle-core/p-04583c51.entry.js +1 -0
  403. package/dist/sparkle-core/{p-6d506f4e.js → p-052caa63.js} +1 -1
  404. package/dist/sparkle-core/{p-016bf847.entry.js → p-057f6a23.entry.js} +1 -1
  405. package/dist/sparkle-core/p-0580419b.entry.js +1 -0
  406. package/dist/sparkle-core/{p-c563b4de.js → p-063cd168.js} +4 -1
  407. package/dist/sparkle-core/p-081968cc.entry.js +1 -0
  408. package/dist/sparkle-core/p-0934f5dd.entry.js +1 -0
  409. package/dist/sparkle-core/{p-3f5d7a08.entry.js → p-11cf398a.entry.js} +1 -1
  410. package/dist/sparkle-core/p-1339830f.entry.js +1 -0
  411. package/dist/sparkle-core/p-145e40f5.entry.js +1 -0
  412. package/dist/sparkle-core/{p-68f3c93d.entry.js → p-1726da2f.entry.js} +1 -1
  413. package/dist/sparkle-core/p-173d5461.entry.js +7 -0
  414. package/dist/sparkle-core/p-18e62133.entry.js +1 -0
  415. package/dist/sparkle-core/p-1af044f7.js +3 -0
  416. package/dist/sparkle-core/p-1b78dea1.entry.js +1 -0
  417. package/dist/sparkle-core/p-1cef8572.js +4 -0
  418. package/dist/sparkle-core/p-1df05176.js +4 -0
  419. package/dist/sparkle-core/p-21bf4ca0.entry.js +1 -0
  420. package/dist/sparkle-core/p-21db4e8e.entry.js +1 -0
  421. package/dist/sparkle-core/p-23a9f7d1.entry.js +1 -0
  422. package/dist/sparkle-core/p-289a35ed.entry.js +1 -0
  423. package/dist/sparkle-core/p-2ee6a5f9.entry.js +1 -0
  424. package/dist/sparkle-core/p-350adbaa.entry.js +1 -0
  425. package/dist/sparkle-core/{p-bccd9036.entry.js → p-35a7bd6c.entry.js} +1 -1
  426. package/dist/sparkle-core/{p-66e3bd1c.entry.js → p-37c00e39.entry.js} +1 -1
  427. package/dist/sparkle-core/p-389500fd.js +4 -0
  428. package/dist/sparkle-core/p-39e5a90f.entry.js +1 -0
  429. package/dist/sparkle-core/{p-ac5e5308.entry.js → p-3a202a38.entry.js} +1 -1
  430. package/dist/sparkle-core/p-3defe550.entry.js +1 -0
  431. package/dist/sparkle-core/p-45e6db62.entry.js +1 -0
  432. package/dist/sparkle-core/{p-581ca370.entry.js → p-48f9b960.entry.js} +1 -1
  433. package/dist/sparkle-core/{p-0efbc0b3.entry.js → p-4dc3ef96.entry.js} +1 -1
  434. package/dist/sparkle-core/p-506221fe.js +4 -0
  435. package/dist/sparkle-core/p-50aac721.entry.js +7 -0
  436. package/dist/sparkle-core/p-513794b0.js +16 -0
  437. package/dist/sparkle-core/{p-2e4e8117.js → p-5264da79.js} +3 -0
  438. package/dist/sparkle-core/{p-40db85ac.entry.js → p-547b70c6.entry.js} +1 -1
  439. package/dist/sparkle-core/p-5598650a.entry.js +1 -0
  440. package/dist/sparkle-core/p-55ae49e1.js +4 -0
  441. package/dist/sparkle-core/p-58e98f89.entry.js +1 -0
  442. package/dist/sparkle-core/p-59f7bf6e.entry.js +1 -0
  443. package/dist/sparkle-core/p-5a3d0e6b.js +4 -0
  444. package/dist/sparkle-core/{p-85d31769.entry.js → p-5b40aae5.entry.js} +1 -1
  445. package/dist/sparkle-core/p-5c9aa1f9.entry.js +4 -0
  446. package/dist/sparkle-core/p-5d2e54ee.entry.js +1 -0
  447. package/dist/sparkle-core/p-5d409601.js +1 -0
  448. package/dist/sparkle-core/{p-afbaad64.entry.js → p-5f45d206.entry.js} +1 -1
  449. package/dist/sparkle-core/p-5ff6416d.entry.js +7 -0
  450. package/dist/sparkle-core/{p-cf2332bb.entry.js → p-62a6c96f.entry.js} +1 -1
  451. package/dist/sparkle-core/p-64e72f8f.js +4 -0
  452. package/dist/sparkle-core/p-660e0742.js +1 -0
  453. package/dist/sparkle-core/{p-d5023db0.entry.js → p-667accac.entry.js} +1 -1
  454. package/dist/sparkle-core/{p-9ca56f5d.entry.js → p-680663a2.entry.js} +1 -1
  455. package/dist/sparkle-core/{p-e975924a.entry.js → p-6823e6c1.entry.js} +1 -1
  456. package/dist/sparkle-core/p-69e7783d.js +4 -0
  457. package/dist/sparkle-core/p-6bbabb80.entry.js +1 -0
  458. package/dist/sparkle-core/p-6bf07a28.js +1 -0
  459. package/dist/sparkle-core/p-6c6145cd.js +4 -0
  460. package/dist/sparkle-core/p-6c90bde6.entry.js +5 -0
  461. package/dist/sparkle-core/p-6e88764b.entry.js +4 -0
  462. package/dist/sparkle-core/p-6ee40949.js +1 -0
  463. package/dist/sparkle-core/p-6fbe3ca3.entry.js +1 -0
  464. package/dist/sparkle-core/{p-f2660943.js → p-6fd4985d.js} +3 -0
  465. package/dist/sparkle-core/{p-8fc9298a.js → p-703ca87c.js} +3 -0
  466. package/dist/sparkle-core/{p-1bf8bed6.entry.js → p-7052c43a.entry.js} +1 -1
  467. package/dist/sparkle-core/{p-111520a0.js → p-70b2452c.js} +3 -0
  468. package/dist/sparkle-core/p-713590fc.js +5 -0
  469. package/dist/sparkle-core/p-7493ee15.entry.js +1 -0
  470. package/dist/sparkle-core/p-75572037.js +1 -0
  471. package/dist/sparkle-core/{p-eb56aa20.entry.js → p-768bcc9e.entry.js} +1 -1
  472. package/dist/sparkle-core/p-797c23ed.entry.js +1 -0
  473. package/dist/sparkle-core/{p-03eb2164.js → p-7c38a70b.js} +1 -1
  474. package/dist/sparkle-core/{p-09d43bee.entry.js → p-7d61177b.entry.js} +1 -1
  475. package/dist/sparkle-core/p-7dbfc316.js +1 -0
  476. package/dist/sparkle-core/p-7e61973d.entry.js +7 -0
  477. package/dist/sparkle-core/{p-3cd28c60.entry.js → p-82e98d07.entry.js} +1 -1
  478. package/dist/sparkle-core/p-838fa86d.entry.js +18 -0
  479. package/dist/sparkle-core/p-855ca600.js +1 -0
  480. package/dist/sparkle-core/p-857f3696.entry.js +1 -0
  481. package/dist/sparkle-core/{p-8f72be08.js → p-8c6b6038.js} +3 -0
  482. package/dist/sparkle-core/p-8fe2e51f.entry.js +4 -0
  483. package/dist/sparkle-core/{p-f72a6e6d.entry.js → p-90389886.entry.js} +1 -1
  484. package/dist/sparkle-core/p-932bfb69.entry.js +1 -0
  485. package/dist/sparkle-core/p-935e7cfc.js +1 -0
  486. package/dist/sparkle-core/{p-c70b9765.entry.js → p-941eaa3a.entry.js} +1 -1
  487. package/dist/sparkle-core/p-95004267.entry.js +1 -0
  488. package/dist/sparkle-core/p-950effe7.entry.js +1 -0
  489. package/dist/sparkle-core/{p-1ca4bf1d.entry.js → p-996361f9.entry.js} +1 -1
  490. package/dist/sparkle-core/p-9a17f2ad.js +4 -0
  491. package/dist/sparkle-core/p-9a443f51.js +1 -1
  492. package/dist/sparkle-core/p-9babd345.js +1 -0
  493. package/dist/sparkle-core/p-9cfdeb18.entry.js +1 -0
  494. package/dist/sparkle-core/p-a080e768.entry.js +1 -0
  495. package/dist/sparkle-core/p-a1cab0f3.js +4 -0
  496. package/dist/sparkle-core/p-a7cc0052.entry.js +4 -0
  497. package/dist/sparkle-core/p-a9ccb0df.js +4 -0
  498. package/dist/sparkle-core/p-a9ee3f6d.entry.js +1 -0
  499. package/dist/sparkle-core/{p-abe2676a.entry.js → p-aa87c7f0.entry.js} +1 -1
  500. package/dist/sparkle-core/{p-e818b11d.entry.js → p-aa9ebc39.entry.js} +1 -1
  501. package/dist/sparkle-core/p-ae1f145d.entry.js +1 -0
  502. package/dist/sparkle-core/{p-73a646fb.entry.js → p-b07a2cf2.entry.js} +1 -1
  503. package/dist/sparkle-core/{p-c82b05e0.entry.js → p-b3909012.entry.js} +1 -1
  504. package/dist/sparkle-core/p-b3e6427d.js +7 -0
  505. package/dist/sparkle-core/p-b49ca0ea.entry.js +1 -0
  506. package/dist/sparkle-core/p-b81e20fe.entry.js +4 -0
  507. package/dist/sparkle-core/p-bca0e465.entry.js +1 -0
  508. package/dist/sparkle-core/p-c1279cc9.entry.js +1 -0
  509. package/dist/sparkle-core/{p-82d95fcd.entry.js → p-c1376096.entry.js} +1 -1
  510. package/dist/sparkle-core/p-c3986a52.entry.js +1 -0
  511. package/dist/sparkle-core/p-c3d3d5c4.entry.js +1 -0
  512. package/dist/sparkle-core/p-c48bbc7c.entry.js +4 -0
  513. package/dist/sparkle-core/p-c5b9bdd6.entry.js +1 -0
  514. package/dist/sparkle-core/{p-15d68269.entry.js → p-c69b0a7a.entry.js} +1 -1
  515. package/dist/sparkle-core/p-cbbeed67.entry.js +1 -0
  516. package/dist/sparkle-core/p-d4a435f8.entry.js +1 -0
  517. package/dist/sparkle-core/p-d4c07aca.js +4 -0
  518. package/dist/sparkle-core/p-d5b05ece.entry.js +5 -0
  519. package/dist/sparkle-core/p-d7baf31e.entry.js +1 -0
  520. package/dist/sparkle-core/p-d8d3524a.js +1 -0
  521. package/dist/sparkle-core/p-df0070c5.entry.js +352 -0
  522. package/dist/sparkle-core/{p-22926eed.entry.js → p-e0fced48.entry.js} +1 -1
  523. package/dist/sparkle-core/p-e1cba44b.entry.js +4 -0
  524. package/dist/sparkle-core/p-e225581a.js +7 -0
  525. package/dist/sparkle-core/{p-4e28ca37.entry.js → p-e3fdd0a8.entry.js} +1 -1
  526. package/dist/sparkle-core/p-e72d4450.js +4 -0
  527. package/dist/sparkle-core/p-eb70a23c.entry.js +1 -0
  528. package/dist/sparkle-core/{p-f9143c5d.entry.js → p-ecd39170.entry.js} +1 -1
  529. package/dist/sparkle-core/{p-151afa9e.entry.js → p-ed0e9d29.entry.js} +1 -1
  530. package/dist/sparkle-core/{p-92d42c10.entry.js → p-ee0d7f19.entry.js} +1 -1
  531. package/dist/sparkle-core/p-f4001fdf.js +4 -0
  532. package/dist/sparkle-core/p-f9b73032.entry.js +1 -0
  533. package/dist/sparkle-core/p-faa912d7.entry.js +1 -0
  534. package/dist/sparkle-core/{p-a250e2ae.entry.js → p-fbd7eeca.entry.js} +1 -1
  535. package/dist/sparkle-core/p-fc933591.entry.js +1 -0
  536. package/dist/sparkle-core/p-fef04ab5.js +4 -0
  537. package/dist/sparkle-core/sparkle-core.css +1 -1
  538. package/dist/sparkle-core/sparkle-core.esm.js +1 -1
  539. package/dist/sparkle-core/svg/balloon-outline.svg +1 -0
  540. package/dist/sparkle-core/svg/balloon-sharp.svg +1 -0
  541. package/dist/sparkle-core/svg/balloon.svg +1 -0
  542. package/dist/sparkle-core/svg/bowling-ball-outline.svg +1 -0
  543. package/dist/sparkle-core/svg/bowling-ball-sharp.svg +1 -0
  544. package/dist/sparkle-core/svg/bowling-ball.svg +1 -0
  545. package/dist/sparkle-core/svg/calendar-number-outline.svg +1 -0
  546. package/dist/sparkle-core/svg/calendar-number-sharp.svg +1 -0
  547. package/dist/sparkle-core/svg/calendar-number.svg +1 -0
  548. package/dist/sparkle-core/svg/diamond-outline.svg +1 -0
  549. package/dist/sparkle-core/svg/diamond-sharp.svg +1 -0
  550. package/dist/sparkle-core/svg/diamond.svg +1 -0
  551. package/dist/sparkle-core/svg/footsteps-outline.svg +1 -0
  552. package/dist/sparkle-core/svg/footsteps-sharp.svg +1 -0
  553. package/dist/sparkle-core/svg/footsteps.svg +1 -0
  554. package/dist/sparkle-core/svg/id-card-outline.svg +1 -0
  555. package/dist/sparkle-core/svg/id-card-sharp.svg +1 -0
  556. package/dist/sparkle-core/svg/id-card.svg +1 -0
  557. package/dist/sparkle-core/svg/logo-apple-ar.svg +1 -0
  558. package/dist/sparkle-core/svg/prism-outline.svg +1 -0
  559. package/dist/sparkle-core/svg/prism-sharp.svg +1 -0
  560. package/dist/sparkle-core/svg/prism.svg +1 -0
  561. package/dist/sparkle-core/svg/scale-outline.svg +1 -0
  562. package/dist/sparkle-core/svg/scale-sharp.svg +1 -0
  563. package/dist/sparkle-core/svg/scale.svg +1 -0
  564. package/dist/sparkle-core/svg/shield-half-outline.svg +1 -0
  565. package/dist/sparkle-core/svg/shield-half-sharp.svg +1 -0
  566. package/dist/sparkle-core/svg/shield-half.svg +1 -0
  567. package/dist/sparkle-core/svg/sparkles-outline.svg +1 -0
  568. package/dist/sparkle-core/svg/sparkles-sharp.svg +1 -0
  569. package/dist/sparkle-core/svg/sparkles.svg +1 -0
  570. package/dist/sparkle-core/swiper/swiper.bundle.js +2 -2
  571. package/dist/types/components/sparkle-animation-player/sparkle-animation-player.d.ts +1 -0
  572. package/dist/types/components/sparkle-character-intro/sparkle-character-intro.d.ts +7 -0
  573. package/dist/types/components/sparkle-course-root/sparkle-course-root.d.ts +2 -2
  574. package/dist/types/components/sparkle-youtube/sparkle-youtube.d.ts +1 -1
  575. package/dist/types/components.d.ts +17 -0
  576. package/dist/types/models/definitions.d.ts +8 -0
  577. package/dist/types/stencil-public-runtime.d.ts +200 -190
  578. package/dist/types/util.d.ts +1 -0
  579. package/package.json +26 -26
  580. package/dist/cjs/app-globals-98121d6d.js +0 -9
  581. package/dist/cjs/button-active-9456fb4d.js +0 -66
  582. package/dist/cjs/feed.service-518d18fd.js +0 -5802
  583. package/dist/cjs/focus-visible-1583bc8e.js +0 -45
  584. package/dist/cjs/framework-delegate-72815681.js +0 -37
  585. package/dist/cjs/header-mobile-collapse_60.cjs.entry.js +0 -86
  586. package/dist/cjs/index.es-baef3314.js +0 -13834
  587. package/dist/cjs/ion-action-sheet.cjs.entry.js +0 -261
  588. package/dist/cjs/ion-alert.cjs.entry.js +0 -455
  589. package/dist/cjs/ion-note.cjs.entry.js +0 -29
  590. package/dist/cjs/ion-popover.cjs.entry.js +0 -365
  591. package/dist/cjs/ion-select-popover.cjs.entry.js +0 -35
  592. package/dist/cjs/status-tap-466a7c6a.js +0 -25
  593. package/dist/esm/app-globals-6451faf3.js +0 -7
  594. package/dist/esm/auth.store-dd944bc2.js +0 -2552
  595. package/dist/esm/button-active-97535443.js +0 -64
  596. package/dist/esm/feed.service-0fda1e36.js +0 -5787
  597. package/dist/esm/focus-visible-abf04ce3.js +0 -43
  598. package/dist/esm/framework-delegate-2c397da3.js +0 -34
  599. package/dist/esm/header-mobile-collapse_60.entry.js +0 -19
  600. package/dist/esm/index.es-a5bf9a49.js +0 -13748
  601. package/dist/esm/ion-action-sheet.entry.js +0 -257
  602. package/dist/esm/ion-alert.entry.js +0 -451
  603. package/dist/esm/ion-note.entry.js +0 -25
  604. package/dist/esm/ion-popover.entry.js +0 -361
  605. package/dist/esm/ion-select-popover.entry.js +0 -31
  606. package/dist/esm/status-tap-9221cd79.js +0 -23
  607. package/dist/sparkle-core/p-019d9d02.entry.js +0 -1
  608. package/dist/sparkle-core/p-02d6d899.js +0 -1
  609. package/dist/sparkle-core/p-03fd27d0.entry.js +0 -1
  610. package/dist/sparkle-core/p-07018d29.js +0 -1
  611. package/dist/sparkle-core/p-083d57a6.entry.js +0 -1
  612. package/dist/sparkle-core/p-090f2624.js +0 -1
  613. package/dist/sparkle-core/p-0e1c7c8c.js +0 -1
  614. package/dist/sparkle-core/p-101feae9.js +0 -1
  615. package/dist/sparkle-core/p-13b0cdfc.entry.js +0 -1
  616. package/dist/sparkle-core/p-13c9bf3a.entry.js +0 -1
  617. package/dist/sparkle-core/p-169920f1.js +0 -1
  618. package/dist/sparkle-core/p-1e1f5e98.entry.js +0 -1
  619. package/dist/sparkle-core/p-1e866c41.entry.js +0 -1
  620. package/dist/sparkle-core/p-2474bf60.entry.js +0 -1
  621. package/dist/sparkle-core/p-25bbf9b4.entry.js +0 -1
  622. package/dist/sparkle-core/p-2a45b732.js +0 -1
  623. package/dist/sparkle-core/p-2abf4d37.entry.js +0 -1
  624. package/dist/sparkle-core/p-2c5edb9f.entry.js +0 -1
  625. package/dist/sparkle-core/p-2d966d35.js +0 -1
  626. package/dist/sparkle-core/p-30b641a4.entry.js +0 -1
  627. package/dist/sparkle-core/p-34ea6639.entry.js +0 -1
  628. package/dist/sparkle-core/p-359422b6.entry.js +0 -1
  629. package/dist/sparkle-core/p-37bfb548.entry.js +0 -1
  630. package/dist/sparkle-core/p-38307b31.js +0 -1
  631. package/dist/sparkle-core/p-3a29a75b.entry.js +0 -1
  632. package/dist/sparkle-core/p-3bb55510.entry.js +0 -1
  633. package/dist/sparkle-core/p-3be0a218.js +0 -1
  634. package/dist/sparkle-core/p-417a8dd6.js +0 -1
  635. package/dist/sparkle-core/p-447163be.entry.js +0 -1
  636. package/dist/sparkle-core/p-49265a8e.entry.js +0 -1
  637. package/dist/sparkle-core/p-4950f841.entry.js +0 -1
  638. package/dist/sparkle-core/p-4b7db0e6.js +0 -1
  639. package/dist/sparkle-core/p-4d8cb365.entry.js +0 -1
  640. package/dist/sparkle-core/p-5073899e.entry.js +0 -1
  641. package/dist/sparkle-core/p-5b366c20.entry.js +0 -1
  642. package/dist/sparkle-core/p-5dce20b9.entry.js +0 -1
  643. package/dist/sparkle-core/p-6006beec.entry.js +0 -1
  644. package/dist/sparkle-core/p-600d04fc.entry.js +0 -1
  645. package/dist/sparkle-core/p-60828739.entry.js +0 -1
  646. package/dist/sparkle-core/p-6112b180.entry.js +0 -1
  647. package/dist/sparkle-core/p-66eb6b7a.entry.js +0 -1
  648. package/dist/sparkle-core/p-67ddec3f.entry.js +0 -1
  649. package/dist/sparkle-core/p-68cb7d41.entry.js +0 -1
  650. package/dist/sparkle-core/p-69cd49de.js +0 -1
  651. package/dist/sparkle-core/p-6edbdde5.entry.js +0 -1
  652. package/dist/sparkle-core/p-6f0ecbe3.js +0 -1
  653. package/dist/sparkle-core/p-765b8593.js +0 -1
  654. package/dist/sparkle-core/p-770128c8.js +0 -1
  655. package/dist/sparkle-core/p-7840618d.js +0 -1
  656. package/dist/sparkle-core/p-7b37d523.entry.js +0 -1
  657. package/dist/sparkle-core/p-7d83d006.entry.js +0 -1
  658. package/dist/sparkle-core/p-7f3d5344.js +0 -1
  659. package/dist/sparkle-core/p-81651f26.entry.js +0 -1
  660. package/dist/sparkle-core/p-86148067.entry.js +0 -1
  661. package/dist/sparkle-core/p-8b5bc1d6.entry.js +0 -1
  662. package/dist/sparkle-core/p-8c3ee44c.entry.js +0 -1
  663. package/dist/sparkle-core/p-9007a06b.entry.js +0 -1
  664. package/dist/sparkle-core/p-90482861.entry.js +0 -1
  665. package/dist/sparkle-core/p-a061537e.entry.js +0 -1
  666. package/dist/sparkle-core/p-a38ea475.js +0 -1
  667. package/dist/sparkle-core/p-ad1ddf1f.js +0 -483
  668. package/dist/sparkle-core/p-aef0bba0.js +0 -1
  669. package/dist/sparkle-core/p-b080c1e3.entry.js +0 -1
  670. package/dist/sparkle-core/p-b11fe0c7.js +0 -1
  671. package/dist/sparkle-core/p-bac45a26.entry.js +0 -1
  672. package/dist/sparkle-core/p-bbe5977b.entry.js +0 -1
  673. package/dist/sparkle-core/p-bc568dcb.js +0 -1
  674. package/dist/sparkle-core/p-bfb55f1d.js +0 -3
  675. package/dist/sparkle-core/p-c163c16d.entry.js +0 -1
  676. package/dist/sparkle-core/p-c3166584.entry.js +0 -1
  677. package/dist/sparkle-core/p-c34269ae.entry.js +0 -1
  678. package/dist/sparkle-core/p-c466ee32.js +0 -1
  679. package/dist/sparkle-core/p-c6710592.entry.js +0 -1
  680. package/dist/sparkle-core/p-c7022391.entry.js +0 -1
  681. package/dist/sparkle-core/p-d4ad796c.js +0 -1
  682. package/dist/sparkle-core/p-d6152660.entry.js +0 -1
  683. package/dist/sparkle-core/p-d63406d8.js +0 -1
  684. package/dist/sparkle-core/p-dba672d5.entry.js +0 -1
  685. package/dist/sparkle-core/p-dd73d01a.entry.js +0 -1
  686. package/dist/sparkle-core/p-de33872d.entry.js +0 -1
  687. package/dist/sparkle-core/p-dee2128a.entry.js +0 -1
  688. package/dist/sparkle-core/p-df07e132.entry.js +0 -1
  689. package/dist/sparkle-core/p-e5d5aaa5.js +0 -1
  690. package/dist/sparkle-core/p-e72c6d87.entry.js +0 -1
  691. package/dist/sparkle-core/p-e8df6ea6.entry.js +0 -1
  692. package/dist/sparkle-core/p-ef2a2172.js +0 -1
  693. package/dist/sparkle-core/p-f1a4ab33.entry.js +0 -1
  694. package/dist/sparkle-core/p-f43ac631.entry.js +0 -1
  695. package/dist/sparkle-core/p-f8063d7b.js +0 -1
  696. package/dist/sparkle-core/p-fd62283e.entry.js +0 -1
  697. package/dist/sparkle-core/p-fef71e0e.entry.js +0 -1
@@ -1,169 +1,826 @@
1
- import { r as registerInstance, e as createEvent, h, H as Host, d as getElement } from './index-55fc9f5e.js';
2
- import { g as getIonMode } from './ionic-global-1f9287cc.js';
3
- import { a as addEventListener, j as clamp, f as findItemLabel, c as renderHiddenInput } from './helpers-e7f66b2b.js';
4
- import './hardware-back-button-508e48cf.js';
5
- import { c as pickerController } from './overlays-8363621c.js';
6
- import { h as hostContext } from './theme-12606872.js';
1
+ import { r as registerInstance, i as createEvent, w as writeTask, h, H as Host, e as getElement } from './index-5568e3fa.js';
2
+ import { d as chevronBack, c as chevronForward, a as chevronDown, f as caretUpSharp, g as caretDownSharp } from './index-dc61f152.js';
3
+ import { g as getIonMode } from './ionic-global-0939c477.js';
4
+ import { startFocusVisible } from './focus-visible-40cda868.js';
5
+ import { k as raf, d as renderHiddenInput, g as getElementRoot } from './helpers-39367fe1.js';
6
+ import { i as isRTL } from './dir-03012648.js';
7
+ import { c as createColorClasses } from './theme-c336c9d9.js';
7
8
 
9
+ /*!
10
+ * (C) Ionic http://ionicframework.com - MIT License
11
+ */
8
12
  /**
9
- * Gets a date value given a format
10
- * Defaults to the current date if
11
- * no date given
13
+ * Returns true if the selected day is equal to the reference day
12
14
  */
13
- const getDateValue = (date, format) => {
14
- const getValue = getValueFromFormat(date, format);
15
- if (getValue !== undefined) {
16
- if (format === FORMAT_A || format === FORMAT_a) {
17
- date.ampm = getValue;
18
- }
19
- return getValue;
20
- }
21
- const defaultDate = parseDate(new Date().toISOString());
22
- return getValueFromFormat(defaultDate, format);
15
+ const isSameDay = (baseParts, compareParts) => {
16
+ return (baseParts.month === compareParts.month &&
17
+ baseParts.day === compareParts.day &&
18
+ baseParts.year === compareParts.year);
23
19
  };
24
- const renderDatetime = (template, value, locale) => {
25
- if (value === undefined) {
26
- return undefined;
20
+ /**
21
+ * Returns true is the selected day is before the reference day.
22
+ */
23
+ const isBefore = (baseParts, compareParts) => {
24
+ return (baseParts.year < compareParts.year ||
25
+ baseParts.year === compareParts.year && baseParts.month < compareParts.month ||
26
+ baseParts.year === compareParts.year && baseParts.month === compareParts.month && baseParts.day < compareParts.day);
27
+ };
28
+ /**
29
+ * Returns true is the selected day is after the reference day.
30
+ */
31
+ const isAfter = (baseParts, compareParts) => {
32
+ return (baseParts.year > compareParts.year ||
33
+ baseParts.year === compareParts.year && baseParts.month > compareParts.month ||
34
+ baseParts.year === compareParts.year && baseParts.month === compareParts.month && baseParts.day > compareParts.day);
35
+ };
36
+
37
+ /*!
38
+ * (C) Ionic http://ionicframework.com - MIT License
39
+ */
40
+ /**
41
+ * Determines if given year is a
42
+ * leap year. Returns `true` if year
43
+ * is a leap year. Returns `false`
44
+ * otherwise.
45
+ */
46
+ const isLeapYear = (year) => {
47
+ return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0);
48
+ };
49
+ const is24Hour = (locale, hourCycle) => {
50
+ /**
51
+ * If developer has explicitly enabled h23 time
52
+ * then return early and do not look at the system default.
53
+ */
54
+ if (hourCycle !== undefined) {
55
+ return hourCycle === 'h23';
27
56
  }
28
- const tokens = [];
29
- let hasText = false;
30
- FORMAT_KEYS.forEach((format, index) => {
31
- if (template.indexOf(format.f) > -1) {
32
- const token = '{' + index + '}';
33
- const text = renderTextFormat(format.f, value[format.k], value, locale);
34
- if (!hasText && text !== undefined && value[format.k] != null) {
35
- hasText = true;
36
- }
37
- tokens.push(token, text || '');
38
- template = template.replace(format.f, token);
39
- }
40
- });
41
- if (!hasText) {
42
- return undefined;
57
+ /**
58
+ * If hourCycle was not specified, check the locale
59
+ * that is set on the user's device. We first check the
60
+ * Intl.DateTimeFormat hourCycle option as developers can encode this
61
+ * option into the locale string. Example: `en-US-u-hc-h23`
62
+ */
63
+ const formatted = new Intl.DateTimeFormat(locale, { hour: 'numeric' });
64
+ const options = formatted.resolvedOptions();
65
+ if (options.hourCycle !== undefined) {
66
+ return options.hourCycle === 'h23';
43
67
  }
44
- for (let i = 0; i < tokens.length; i += 2) {
45
- template = template.replace(tokens[i], tokens[i + 1]);
68
+ /**
69
+ * If hourCycle is not specified (either through lack
70
+ * of browser support or locale information) then fall
71
+ * back to this slower hourCycle check.
72
+ */
73
+ const date = new Date('5/18/2021 00:00');
74
+ const parts = formatted.formatToParts(date);
75
+ const hour = parts.find(p => p.type === 'hour');
76
+ if (!hour) {
77
+ throw new Error('Hour value not found from DateTimeFormat');
46
78
  }
47
- return template;
79
+ return hour.value === '00';
48
80
  };
49
- const renderTextFormat = (format, value, date, locale) => {
50
- if ((format === FORMAT_DDDD || format === FORMAT_DDD)) {
51
- try {
52
- value = (new Date(date.year, date.month - 1, date.day)).getDay();
53
- if (format === FORMAT_DDDD) {
54
- return (locale.dayNames ? locale.dayNames : DAY_NAMES)[value];
81
+ /**
82
+ * Given a date object, returns the number
83
+ * of days in that month.
84
+ * Month value begin at 1, not 0.
85
+ * i.e. January = month 1.
86
+ */
87
+ const getNumDaysInMonth = (month, year) => {
88
+ return (month === 4 || month === 6 || month === 9 || month === 11) ? 30 : (month === 2) ? isLeapYear(year) ? 29 : 28 : 31;
89
+ };
90
+ /**
91
+ * Certain locales display month then year while
92
+ * others display year then month.
93
+ * We can use Intl.DateTimeFormat to determine
94
+ * the ordering for each locale.
95
+ */
96
+ const isMonthFirstLocale = (locale) => {
97
+ /**
98
+ * By setting month and year we guarantee that only
99
+ * month, year, and literal (slashes '/', for example)
100
+ * values are included in the formatToParts results.
101
+ *
102
+ * The ordering of the parts will be determined by
103
+ * the locale. So if the month is the first value,
104
+ * then we know month should be shown first. If the
105
+ * year is the first value, then we know year should be shown first.
106
+ *
107
+ * This ordering can be controlled by customizing the locale property.
108
+ */
109
+ const parts = new Intl.DateTimeFormat(locale, { month: 'numeric', year: 'numeric' }).formatToParts(new Date());
110
+ return parts[0].type === 'month';
111
+ };
112
+
113
+ /*!
114
+ * (C) Ionic http://ionicframework.com - MIT License
115
+ */
116
+ const twoDigit = (val) => {
117
+ return ('0' + (val !== undefined ? Math.abs(val) : '0')).slice(-2);
118
+ };
119
+ const fourDigit = (val) => {
120
+ return ('000' + (val !== undefined ? Math.abs(val) : '0')).slice(-4);
121
+ };
122
+ const convertDataToISO = (data) => {
123
+ // https://www.w3.org/TR/NOTE-datetime
124
+ let rtn = '';
125
+ if (data.year !== undefined) {
126
+ // YYYY
127
+ rtn = fourDigit(data.year);
128
+ if (data.month !== undefined) {
129
+ // YYYY-MM
130
+ rtn += '-' + twoDigit(data.month);
131
+ if (data.day !== undefined) {
132
+ // YYYY-MM-DD
133
+ rtn += '-' + twoDigit(data.day);
134
+ if (data.hour !== undefined) {
135
+ // YYYY-MM-DDTHH:mm:SS
136
+ rtn += `T${twoDigit(data.hour)}:${twoDigit(data.minute)}:00`;
137
+ if (data.tzOffset === undefined) {
138
+ // YYYY-MM-DDTHH:mm:SSZ
139
+ rtn += 'Z';
140
+ }
141
+ else {
142
+ // YYYY-MM-DDTHH:mm:SS+/-HH:mm
143
+ rtn += (data.tzOffset > 0 ? '+' : '-') + twoDigit(Math.floor(Math.abs(data.tzOffset / 60))) + ':' + twoDigit(data.tzOffset % 60);
144
+ }
145
+ }
55
146
  }
56
- return (locale.dayShortNames ? locale.dayShortNames : DAY_SHORT_NAMES)[value];
57
147
  }
58
- catch (e) {
59
- // ignore
148
+ }
149
+ else if (data.hour !== undefined) {
150
+ // HH:mm
151
+ rtn = twoDigit(data.hour) + ':' + twoDigit(data.minute);
152
+ }
153
+ return rtn;
154
+ };
155
+ /**
156
+ * Converts an 12 hour value to 24 hours.
157
+ */
158
+ const convert12HourTo24Hour = (hour, ampm) => {
159
+ if (ampm === undefined) {
160
+ return hour;
161
+ }
162
+ /**
163
+ * If AM and 12am
164
+ * then return 00:00.
165
+ * Otherwise just return
166
+ * the hour since it is
167
+ * already in 24 hour format.
168
+ */
169
+ if (ampm === 'am') {
170
+ if (hour === 12) {
171
+ return 0;
60
172
  }
61
- return undefined;
173
+ return hour;
62
174
  }
63
- if (format === FORMAT_A) {
64
- return date !== undefined && date.hour !== undefined
65
- ? (date.hour < 12 ? 'AM' : 'PM')
66
- : value ? value.toUpperCase() : '';
175
+ /**
176
+ * If PM and 12pm
177
+ * just return 12:00
178
+ * since it is already
179
+ * in 24 hour format.
180
+ * Otherwise add 12 hours
181
+ * to the time.
182
+ */
183
+ if (hour === 12) {
184
+ return 12;
67
185
  }
68
- if (format === FORMAT_a) {
69
- return date !== undefined && date.hour !== undefined
70
- ? (date.hour < 12 ? 'am' : 'pm')
71
- : value || '';
186
+ return hour + 12;
187
+ };
188
+ const getStartOfWeek = (refParts) => {
189
+ const { dayOfWeek } = refParts;
190
+ if (dayOfWeek === null || dayOfWeek === undefined) {
191
+ throw new Error('No day of week provided');
72
192
  }
73
- if (value == null) {
74
- return '';
193
+ return subtractDays(refParts, dayOfWeek);
194
+ };
195
+ const getEndOfWeek = (refParts) => {
196
+ const { dayOfWeek } = refParts;
197
+ if (dayOfWeek === null || dayOfWeek === undefined) {
198
+ throw new Error('No day of week provided');
75
199
  }
76
- if (format === FORMAT_YY || format === FORMAT_MM ||
77
- format === FORMAT_DD || format === FORMAT_HH ||
78
- format === FORMAT_mm || format === FORMAT_ss) {
79
- return twoDigit(value);
200
+ return addDays(refParts, 6 - dayOfWeek);
201
+ };
202
+ const getNextDay = (refParts) => {
203
+ return addDays(refParts, 1);
204
+ };
205
+ const getPreviousDay = (refParts) => {
206
+ return subtractDays(refParts, 1);
207
+ };
208
+ const getPreviousWeek = (refParts) => {
209
+ return subtractDays(refParts, 7);
210
+ };
211
+ const getNextWeek = (refParts) => {
212
+ return addDays(refParts, 7);
213
+ };
214
+ /**
215
+ * Given datetime parts, subtract
216
+ * numDays from the date.
217
+ * Returns a new DatetimeParts object
218
+ * Currently can only go backward at most 1 month.
219
+ */
220
+ const subtractDays = (refParts, numDays) => {
221
+ const { month, day, year } = refParts;
222
+ if (day === null) {
223
+ throw new Error('No day provided');
80
224
  }
81
- if (format === FORMAT_YYYY) {
82
- return fourDigit(value);
225
+ const workingParts = {
226
+ month,
227
+ day,
228
+ year
229
+ };
230
+ workingParts.day = day - numDays;
231
+ /**
232
+ * If wrapping to previous month
233
+ * update days and decrement month
234
+ */
235
+ if (workingParts.day < 1) {
236
+ workingParts.month -= 1;
83
237
  }
84
- if (format === FORMAT_MMMM) {
85
- return (locale.monthNames ? locale.monthNames : MONTH_NAMES)[value - 1];
238
+ /**
239
+ * If moving to previous year, reset
240
+ * month to December and decrement year
241
+ */
242
+ if (workingParts.month < 1) {
243
+ workingParts.month = 12;
244
+ workingParts.year -= 1;
86
245
  }
87
- if (format === FORMAT_MMM) {
88
- return (locale.monthShortNames ? locale.monthShortNames : MONTH_SHORT_NAMES)[value - 1];
246
+ /**
247
+ * Determine how many days are in the current
248
+ * month
249
+ */
250
+ if (workingParts.day < 1) {
251
+ const daysInMonth = getNumDaysInMonth(workingParts.month, workingParts.year);
252
+ /**
253
+ * Take num days in month and add the
254
+ * number of underflow days. This number will
255
+ * be negative.
256
+ * Example: 1 week before Jan 2, 2021 is
257
+ * December 26, 2021 so:
258
+ * 2 - 7 = -5
259
+ * 31 + (-5) = 26
260
+ */
261
+ workingParts.day = daysInMonth + workingParts.day;
262
+ }
263
+ return workingParts;
264
+ };
265
+ /**
266
+ * Given datetime parts, add
267
+ * numDays to the date.
268
+ * Returns a new DatetimeParts object
269
+ * Currently can only go forward at most 1 month.
270
+ */
271
+ const addDays = (refParts, numDays) => {
272
+ const { month, day, year } = refParts;
273
+ if (day === null) {
274
+ throw new Error('No day provided');
275
+ }
276
+ const workingParts = {
277
+ month,
278
+ day,
279
+ year
280
+ };
281
+ const daysInMonth = getNumDaysInMonth(month, year);
282
+ workingParts.day = day + numDays;
283
+ /**
284
+ * If wrapping to next month
285
+ * update days and increment month
286
+ */
287
+ if (workingParts.day > daysInMonth) {
288
+ workingParts.day -= daysInMonth;
289
+ workingParts.month += 1;
89
290
  }
90
- if (format === FORMAT_hh || format === FORMAT_h) {
91
- if (value === 0) {
92
- return '12';
291
+ /**
292
+ * If moving to next year, reset
293
+ * month to January and increment year
294
+ */
295
+ if (workingParts.month > 12) {
296
+ workingParts.month = 1;
297
+ workingParts.year += 1;
298
+ }
299
+ return workingParts;
300
+ };
301
+ /**
302
+ * Given DatetimeParts, generate the previous month.
303
+ */
304
+ const getPreviousMonth = (refParts) => {
305
+ /**
306
+ * If current month is January, wrap backwards
307
+ * to December of the previous year.
308
+ */
309
+ const month = (refParts.month === 1) ? 12 : refParts.month - 1;
310
+ const year = (refParts.month === 1) ? refParts.year - 1 : refParts.year;
311
+ const numDaysInMonth = getNumDaysInMonth(month, year);
312
+ const day = (numDaysInMonth < refParts.day) ? numDaysInMonth : refParts.day;
313
+ return { month, year, day };
314
+ };
315
+ /**
316
+ * Given DatetimeParts, generate the next month.
317
+ */
318
+ const getNextMonth = (refParts) => {
319
+ /**
320
+ * If current month is December, wrap forwards
321
+ * to January of the next year.
322
+ */
323
+ const month = (refParts.month === 12) ? 1 : refParts.month + 1;
324
+ const year = (refParts.month === 12) ? refParts.year + 1 : refParts.year;
325
+ const numDaysInMonth = getNumDaysInMonth(month, year);
326
+ const day = (numDaysInMonth < refParts.day) ? numDaysInMonth : refParts.day;
327
+ return { month, year, day };
328
+ };
329
+ const changeYear = (refParts, yearDelta) => {
330
+ const month = refParts.month;
331
+ const year = refParts.year + yearDelta;
332
+ const numDaysInMonth = getNumDaysInMonth(month, year);
333
+ const day = (numDaysInMonth < refParts.day) ? numDaysInMonth : refParts.day;
334
+ return { month, year, day };
335
+ };
336
+ /**
337
+ * Given DatetimeParts, generate the previous year.
338
+ */
339
+ const getPreviousYear = (refParts) => {
340
+ return changeYear(refParts, -1);
341
+ };
342
+ /**
343
+ * Given DatetimeParts, generate the next year.
344
+ */
345
+ const getNextYear = (refParts) => {
346
+ return changeYear(refParts, 1);
347
+ };
348
+ /**
349
+ * If PM, then internal value should
350
+ * be converted to 24-hr time.
351
+ * Does not apply when public
352
+ * values are already 24-hr time.
353
+ */
354
+ const getInternalHourValue = (hour, use24Hour, ampm) => {
355
+ if (use24Hour) {
356
+ return hour;
357
+ }
358
+ return convert12HourTo24Hour(hour, ampm);
359
+ };
360
+ /**
361
+ * Unless otherwise stated, all month values are
362
+ * 1 indexed instead of the typical 0 index in JS Date.
363
+ * Example:
364
+ * January = Month 0 when using JS Date
365
+ * January = Month 1 when using this datetime util
366
+ */
367
+ /**
368
+ * Given the current datetime parts and a new AM/PM value
369
+ * calculate what the hour should be in 24-hour time format.
370
+ * Used when toggling the AM/PM segment since we store our hours
371
+ * in 24-hour time format internally.
372
+ */
373
+ const calculateHourFromAMPM = (currentParts, newAMPM) => {
374
+ const { ampm: currentAMPM, hour } = currentParts;
375
+ let newHour = hour;
376
+ /**
377
+ * If going from AM --> PM, need to update the
378
+ *
379
+ */
380
+ if (currentAMPM === 'am' && newAMPM === 'pm') {
381
+ newHour = convert12HourTo24Hour(newHour, 'pm');
382
+ /**
383
+ * If going from PM --> AM
384
+ */
385
+ }
386
+ else if (currentAMPM === 'pm' && newAMPM === 'am') {
387
+ newHour = Math.abs(newHour - 12);
388
+ }
389
+ return newHour;
390
+ };
391
+
392
+ /*!
393
+ * (C) Ionic http://ionicframework.com - MIT License
394
+ */
395
+ /**
396
+ * Returns the current date as
397
+ * an ISO string in the user's
398
+ * timezone.
399
+ */
400
+ const getToday = () => {
401
+ /**
402
+ * Grab the current date object
403
+ * as well as the timezone offset
404
+ */
405
+ const date = new Date();
406
+ const tzOffset = date.getTimezoneOffset();
407
+ /**
408
+ * When converting to ISO string, everything is
409
+ * set to UTC. Since we want to show these dates
410
+ * relative to the user's timezone, we need to
411
+ * subtract the timezone offset from the date
412
+ * so that when `toISOString()` adds it back
413
+ * there was a net change of zero hours from the
414
+ * local date.
415
+ */
416
+ date.setHours(date.getHours() - (tzOffset / 60));
417
+ return date.toISOString();
418
+ };
419
+ const minutes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59];
420
+ const hour12 = [12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
421
+ const hour23 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23];
422
+ /**
423
+ * Given a locale and a mode,
424
+ * return an array with formatted days
425
+ * of the week. iOS should display days
426
+ * such as "Mon" or "Tue".
427
+ * MD should display days such as "M"
428
+ * or "T".
429
+ */
430
+ const getDaysOfWeek = (locale, mode, firstDayOfWeek = 0) => {
431
+ /**
432
+ * Nov 1st, 2020 starts on a Sunday.
433
+ * ion-datetime assumes weeks start on Sunday,
434
+ * but is configurable via `firstDayOfWeek`.
435
+ */
436
+ const weekdayFormat = mode === 'ios' ? 'short' : 'narrow';
437
+ const intl = new Intl.DateTimeFormat(locale, { weekday: weekdayFormat });
438
+ const startDate = new Date('11/01/2020');
439
+ const daysOfWeek = [];
440
+ /**
441
+ * For each day of the week,
442
+ * get the day name.
443
+ */
444
+ for (let i = firstDayOfWeek; i < firstDayOfWeek + 7; i++) {
445
+ const currentDate = new Date(startDate);
446
+ currentDate.setDate(currentDate.getDate() + i);
447
+ daysOfWeek.push(intl.format(currentDate));
448
+ }
449
+ return daysOfWeek;
450
+ };
451
+ /**
452
+ * Returns an array containing all of the
453
+ * days in a month for a given year. Values are
454
+ * aligned with a week calendar starting on
455
+ * the firstDayOfWeek value (Sunday by default)
456
+ * using null values.
457
+ */
458
+ const getDaysOfMonth = (month, year, firstDayOfWeek) => {
459
+ const numDays = getNumDaysInMonth(month, year);
460
+ const firstOfMonth = new Date(`${month}/1/${year}`).getDay();
461
+ /**
462
+ * To get the first day of the month aligned on the correct
463
+ * day of the week, we need to determine how many "filler" days
464
+ * to generate. These filler days as empty/disabled buttons
465
+ * that fill the space of the days of the week before the first
466
+ * of the month.
467
+ *
468
+ * There are two cases here:
469
+ *
470
+ * 1. If firstOfMonth = 4, firstDayOfWeek = 0 then the offset
471
+ * is (4 - (0 + 1)) = 3. Since the offset loop goes from 0 to 3 inclusive,
472
+ * this will generate 4 filler days (0, 1, 2, 3), and then day of week 4 will have
473
+ * the first day of the month.
474
+ *
475
+ * 2. If firstOfMonth = 2, firstDayOfWeek = 4 then the offset
476
+ * is (6 - (4 - 2)) = 4. Since the offset loop goes from 0 to 4 inclusive,
477
+ * this will generate 5 filler days (0, 1, 2, 3, 4), and then day of week 5 will have
478
+ * the first day of the month.
479
+ */
480
+ const offset = firstOfMonth >= firstDayOfWeek ? firstOfMonth - (firstDayOfWeek + 1) : 6 - (firstDayOfWeek - firstOfMonth);
481
+ let days = [];
482
+ for (let i = 1; i <= numDays; i++) {
483
+ days.push({ day: i, dayOfWeek: (offset + i) % 7 });
484
+ }
485
+ for (let i = 0; i <= offset; i++) {
486
+ days = [
487
+ { day: null, dayOfWeek: null },
488
+ ...days
489
+ ];
490
+ }
491
+ return days;
492
+ };
493
+ /**
494
+ * Given a local, reference datetime parts and option
495
+ * max/min bound datetime parts, calculate the acceptable
496
+ * hour and minute values according to the bounds and locale.
497
+ */
498
+ const generateTime = (refParts, hourCycle = 'h12', minParts, maxParts, hourValues, minuteValues) => {
499
+ const use24Hour = hourCycle === 'h23';
500
+ let processedHours = use24Hour ? hour23 : hour12;
501
+ let processedMinutes = minutes;
502
+ let isAMAllowed = true;
503
+ let isPMAllowed = true;
504
+ if (hourValues) {
505
+ processedHours = processedHours.filter(hour => hourValues.includes(hour));
506
+ }
507
+ if (minuteValues) {
508
+ processedMinutes = processedMinutes.filter(minute => minuteValues.includes(minute));
509
+ }
510
+ if (minParts) {
511
+ /**
512
+ * If ref day is the same as the
513
+ * minimum allowed day, filter hour/minute
514
+ * values according to min hour and minute.
515
+ */
516
+ if (isSameDay(refParts, minParts)) {
517
+ /**
518
+ * Users may not always set the hour/minute for
519
+ * min value (i.e. 2021-06-02) so we should allow
520
+ * all hours/minutes in that case.
521
+ */
522
+ if (minParts.hour !== undefined) {
523
+ processedHours = processedHours.filter(hour => {
524
+ const convertedHour = refParts.ampm === 'pm' ? (hour + 12) % 24 : hour;
525
+ return (use24Hour ? hour : convertedHour) >= minParts.hour;
526
+ });
527
+ isAMAllowed = minParts.hour < 13;
528
+ }
529
+ if (minParts.minute !== undefined) {
530
+ /**
531
+ * The minimum minute range should not be enforced when
532
+ * the hour is greater than the min hour.
533
+ *
534
+ * For example with a minimum range of 09:30, users
535
+ * should be able to select 10:00-10:29 and beyond.
536
+ */
537
+ let isPastMinHour = false;
538
+ if (minParts.hour !== undefined && refParts.hour !== undefined) {
539
+ if (refParts.hour > minParts.hour) {
540
+ isPastMinHour = true;
541
+ }
542
+ }
543
+ processedMinutes = processedMinutes.filter(minute => {
544
+ if (isPastMinHour) {
545
+ return true;
546
+ }
547
+ return minute >= minParts.minute;
548
+ });
549
+ }
550
+ /**
551
+ * If ref day is before minimum
552
+ * day do not render any hours/minute values
553
+ */
93
554
  }
94
- if (value > 12) {
95
- value -= 12;
555
+ else if (isBefore(refParts, minParts)) {
556
+ processedHours = [];
557
+ processedMinutes = [];
558
+ isAMAllowed = isPMAllowed = false;
96
559
  }
97
- if (format === FORMAT_hh && value < 10) {
98
- return ('0' + value);
560
+ }
561
+ if (maxParts) {
562
+ /**
563
+ * If ref day is the same as the
564
+ * maximum allowed day, filter hour/minute
565
+ * values according to max hour and minute.
566
+ */
567
+ if (isSameDay(refParts, maxParts)) {
568
+ /**
569
+ * Users may not always set the hour/minute for
570
+ * max value (i.e. 2021-06-02) so we should allow
571
+ * all hours/minutes in that case.
572
+ */
573
+ if (maxParts.hour !== undefined) {
574
+ processedHours = processedHours.filter(hour => {
575
+ const convertedHour = refParts.ampm === 'pm' ? (hour + 12) % 24 : hour;
576
+ return (use24Hour ? hour : convertedHour) <= maxParts.hour;
577
+ });
578
+ isPMAllowed = maxParts.hour >= 13;
579
+ }
580
+ if (maxParts.minute !== undefined && refParts.hour === maxParts.hour) {
581
+ // The available minutes should only be filtered when the hour is the same as the max hour.
582
+ // For example if the max hour is 10:30 and the current hour is 10:00,
583
+ // users should be able to select 00-30 minutes.
584
+ // If the current hour is 09:00, users should be able to select 00-60 minutes.
585
+ processedMinutes = processedMinutes.filter(minute => minute <= maxParts.minute);
586
+ }
587
+ /**
588
+ * If ref day is after minimum
589
+ * day do not render any hours/minute values
590
+ */
591
+ }
592
+ else if (isAfter(refParts, maxParts)) {
593
+ processedHours = [];
594
+ processedMinutes = [];
595
+ isAMAllowed = isPMAllowed = false;
99
596
  }
100
597
  }
101
- return value.toString();
598
+ return {
599
+ hours: processedHours,
600
+ minutes: processedMinutes,
601
+ am: isAMAllowed,
602
+ pm: isPMAllowed
603
+ };
102
604
  };
103
- const dateValueRange = (format, min, max) => {
104
- const opts = [];
105
- if (format === FORMAT_YYYY || format === FORMAT_YY) {
106
- // year
107
- if (max.year === undefined || min.year === undefined) {
108
- throw new Error('min and max year is undefined');
605
+ /**
606
+ * Given DatetimeParts, generate the previous,
607
+ * current, and and next months.
608
+ */
609
+ const generateMonths = (refParts) => {
610
+ return [
611
+ getPreviousMonth(refParts),
612
+ { month: refParts.month, year: refParts.year, day: refParts.day },
613
+ getNextMonth(refParts)
614
+ ];
615
+ };
616
+ const getPickerMonths = (locale, refParts, minParts, maxParts, monthValues) => {
617
+ const { year } = refParts;
618
+ const months = [];
619
+ if (monthValues !== undefined) {
620
+ let processedMonths = monthValues;
621
+ if ((maxParts === null || maxParts === void 0 ? void 0 : maxParts.month) !== undefined) {
622
+ processedMonths = processedMonths.filter(month => month <= maxParts.month);
109
623
  }
110
- for (let i = max.year; i >= min.year; i--) {
111
- opts.push(i);
624
+ if ((minParts === null || minParts === void 0 ? void 0 : minParts.month) !== undefined) {
625
+ processedMonths = processedMonths.filter(month => month >= minParts.month);
112
626
  }
627
+ processedMonths.forEach(processedMonth => {
628
+ const date = new Date(`${processedMonth}/1/${year} GMT+0000`);
629
+ const monthString = new Intl.DateTimeFormat(locale, { month: 'long', timeZone: 'UTC' }).format(date);
630
+ months.push({ text: monthString, value: processedMonth });
631
+ });
113
632
  }
114
- else if (format === FORMAT_MMMM || format === FORMAT_MMM ||
115
- format === FORMAT_MM || format === FORMAT_M ||
116
- format === FORMAT_hh || format === FORMAT_h) {
117
- // month or 12-hour
118
- for (let i = 1; i < 13; i++) {
119
- opts.push(i);
633
+ else {
634
+ const maxMonth = maxParts && maxParts.year === year ? maxParts.month : 12;
635
+ const minMonth = minParts && minParts.year === year ? minParts.month : 1;
636
+ for (let i = minMonth; i <= maxMonth; i++) {
637
+ /**
638
+ *
639
+ * There is a bug on iOS 14 where
640
+ * Intl.DateTimeFormat takes into account
641
+ * the local timezone offset when formatting dates.
642
+ *
643
+ * Forcing the timezone to 'UTC' fixes the issue. However,
644
+ * we should keep this workaround as it is safer. In the event
645
+ * this breaks in another browser, we will not be impacted
646
+ * because all dates will be interpreted in UTC.
647
+ *
648
+ * Example:
649
+ * new Intl.DateTimeFormat('en-US', { month: 'long' }).format(new Date('Sat Apr 01 2006 00:00:00 GMT-0400 (EDT)')) // "March"
650
+ * new Intl.DateTimeFormat('en-US', { month: 'long', timeZone: 'UTC' }).format(new Date('Sat Apr 01 2006 00:00:00 GMT-0400 (EDT)')) // "April"
651
+ *
652
+ * In certain timezones, iOS 14 shows the wrong
653
+ * date for .toUTCString(). To combat this, we
654
+ * force all of the timezones to GMT+0000 (UTC).
655
+ *
656
+ * Example:
657
+ * Time Zone: Central European Standard Time
658
+ * new Date('1/1/1992').toUTCString() // "Tue, 31 Dec 1991 23:00:00 GMT"
659
+ * new Date('1/1/1992 GMT+0000').toUTCString() // "Wed, 01 Jan 1992 00:00:00 GMT"
660
+ */
661
+ const date = new Date(`${i}/1/${year} GMT+0000`);
662
+ const monthString = new Intl.DateTimeFormat(locale, { month: 'long', timeZone: 'UTC' }).format(date);
663
+ months.push({ text: monthString, value: i });
120
664
  }
121
665
  }
122
- else if (format === FORMAT_DDDD || format === FORMAT_DDD ||
123
- format === FORMAT_DD || format === FORMAT_D) {
124
- // day
125
- for (let i = 1; i < 32; i++) {
126
- opts.push(i);
666
+ return months;
667
+ };
668
+ const getCalendarYears = (refParts, minParts, maxParts, yearValues) => {
669
+ if (yearValues !== undefined) {
670
+ let processedYears = yearValues;
671
+ if ((maxParts === null || maxParts === void 0 ? void 0 : maxParts.year) !== undefined) {
672
+ processedYears = processedYears.filter(year => year <= maxParts.year);
127
673
  }
128
- }
129
- else if (format === FORMAT_HH || format === FORMAT_H) {
130
- // 24-hour
131
- for (let i = 0; i < 24; i++) {
132
- opts.push(i);
674
+ if ((minParts === null || minParts === void 0 ? void 0 : minParts.year) !== undefined) {
675
+ processedYears = processedYears.filter(year => year >= minParts.year);
133
676
  }
677
+ return processedYears;
134
678
  }
135
- else if (format === FORMAT_mm || format === FORMAT_m) {
136
- // minutes
137
- for (let i = 0; i < 60; i++) {
138
- opts.push(i);
679
+ else {
680
+ const { year } = refParts;
681
+ const maxYear = ((maxParts === null || maxParts === void 0 ? void 0 : maxParts.year) || year);
682
+ const minYear = ((minParts === null || minParts === void 0 ? void 0 : minParts.year) || year - 100);
683
+ const years = [];
684
+ for (let i = maxYear; i >= minYear; i--) {
685
+ years.push(i);
139
686
  }
687
+ return years;
140
688
  }
141
- else if (format === FORMAT_ss || format === FORMAT_s) {
142
- // seconds
143
- for (let i = 0; i < 60; i++) {
144
- opts.push(i);
145
- }
689
+ };
690
+
691
+ /*!
692
+ * (C) Ionic http://ionicframework.com - MIT License
693
+ */
694
+ const get12HourTime = (hour) => {
695
+ return hour % 12 || 12;
696
+ };
697
+ const getFormattedAMPM = (ampm) => {
698
+ if (ampm === undefined) {
699
+ return '';
700
+ }
701
+ return ampm.toUpperCase();
702
+ };
703
+ const getFormattedTime = (refParts, use24Hour) => {
704
+ if (refParts.hour === undefined || refParts.minute === undefined) {
705
+ return 'Invalid Time';
146
706
  }
147
- else if (format === FORMAT_A || format === FORMAT_a) {
148
- // AM/PM
149
- opts.push('am', 'pm');
707
+ const hour = use24Hour ? getFormattedHour(refParts.hour, use24Hour) : get12HourTime(refParts.hour);
708
+ const minute = addTimePadding(refParts.minute);
709
+ if (use24Hour) {
710
+ return `${hour}:${minute}`;
150
711
  }
151
- return opts;
712
+ return `${hour}:${minute} ${getFormattedAMPM(refParts.ampm)}`;
152
713
  };
153
- const dateSortValue = (year, month, day, hour = 0, minute = 0) => {
154
- return parseInt(`1${fourDigit(year)}${twoDigit(month)}${twoDigit(day)}${twoDigit(hour)}${twoDigit(minute)}`, 10);
714
+ /**
715
+ * Adds padding to a time value so
716
+ * that it is always 2 digits.
717
+ */
718
+ const addTimePadding = (value) => {
719
+ const valueToString = value.toString();
720
+ if (valueToString.length > 1) {
721
+ return valueToString;
722
+ }
723
+ return `0${valueToString}`;
155
724
  };
156
- const dateDataSortValue = (data) => {
157
- return dateSortValue(data.year, data.month, data.day, data.hour, data.minute);
725
+ /**
726
+ * Formats the hour value so that it
727
+ * is always 2 digits. Only applies
728
+ * if using 12 hour format.
729
+ */
730
+ const getFormattedHour = (hour, use24Hour) => {
731
+ if (!use24Hour) {
732
+ return hour.toString();
733
+ }
734
+ return addTimePadding(hour);
158
735
  };
159
- const daysInMonth = (month, year) => {
160
- return (month === 4 || month === 6 || month === 9 || month === 11) ? 30 : (month === 2) ? isLeapYear(year) ? 29 : 28 : 31;
736
+ /**
737
+ * Generates an aria-label to be read by screen readers
738
+ * given a local, a date, and whether or not that date is
739
+ * today's date.
740
+ */
741
+ const generateDayAriaLabel = (locale, today, refParts) => {
742
+ if (refParts.day === null) {
743
+ return null;
744
+ }
745
+ /**
746
+ * MM/DD/YYYY will return midnight in the user's timezone.
747
+ */
748
+ const date = new Date(`${refParts.month}/${refParts.day}/${refParts.year} GMT+0000`);
749
+ const labelString = new Intl.DateTimeFormat(locale, { weekday: 'long', month: 'long', day: 'numeric', timeZone: 'UTC' }).format(date);
750
+ /**
751
+ * If date is today, prepend "Today" so screen readers indicate
752
+ * that the date is today.
753
+ */
754
+ return (today) ? `Today, ${labelString}` : labelString;
161
755
  };
162
- const isLeapYear = (year) => {
163
- return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0);
756
+ /**
757
+ * Gets the day of the week, month, and day
758
+ * Used for the header in MD mode.
759
+ */
760
+ const getMonthAndDay = (locale, refParts) => {
761
+ const date = new Date(`${refParts.month}/${refParts.day}/${refParts.year} GMT+0000`);
762
+ return new Intl.DateTimeFormat(locale, { weekday: 'short', month: 'short', day: 'numeric', timeZone: 'UTC' }).format(date);
763
+ };
764
+ /**
765
+ * Given a locale and a date object,
766
+ * return a formatted string that includes
767
+ * the month name and full year.
768
+ * Example: May 2021
769
+ */
770
+ const getMonthAndYear = (locale, refParts) => {
771
+ const date = new Date(`${refParts.month}/${refParts.day}/${refParts.year} GMT+0000`);
772
+ return new Intl.DateTimeFormat(locale, { month: 'long', year: 'numeric', timeZone: 'UTC' }).format(date);
164
773
  };
774
+
775
+ /*!
776
+ * (C) Ionic http://ionicframework.com - MIT License
777
+ */
165
778
  const ISO_8601_REGEXP = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/;
166
779
  const TIME_REGEXP = /^((\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/;
780
+ /**
781
+ * Use to convert a string of comma separated numbers or
782
+ * an array of numbers, and clean up any user input
783
+ */
784
+ const convertToArrayOfNumbers = (input) => {
785
+ if (input === undefined) {
786
+ return;
787
+ }
788
+ let processedInput = input;
789
+ if (typeof input === 'string') {
790
+ // convert the string to an array of strings
791
+ // auto remove any whitespace and [] characters
792
+ processedInput = input.replace(/\[|\]|\s/g, '').split(',');
793
+ }
794
+ let values;
795
+ if (Array.isArray(processedInput)) {
796
+ // ensure each value is an actual number in the returned array
797
+ values = processedInput
798
+ .map((num) => parseInt(num, 10))
799
+ .filter(isFinite);
800
+ }
801
+ else {
802
+ values = [processedInput];
803
+ }
804
+ return values;
805
+ };
806
+ /**
807
+ * Extracts date information
808
+ * from a .calendar-day element
809
+ * into DatetimeParts.
810
+ */
811
+ const getPartsFromCalendarDay = (el) => {
812
+ return {
813
+ month: parseInt(el.getAttribute('data-month'), 10),
814
+ day: parseInt(el.getAttribute('data-day'), 10),
815
+ year: parseInt(el.getAttribute('data-year'), 10),
816
+ dayOfWeek: parseInt(el.getAttribute('data-day-of-week'), 10)
817
+ };
818
+ };
819
+ /**
820
+ * Given an ISO-8601 string, format out the parts
821
+ * We do not use the JS Date object here because
822
+ * it adjusts the date for the current timezone.
823
+ */
167
824
  const parseDate = (val) => {
168
825
  // manually parse IS0 cuz Date.parse cannot be trusted
169
826
  // ISO 8601 format: 1994-12-15T13:47:20Z
@@ -213,356 +870,133 @@ const parseDate = (val) => {
213
870
  tzOffset,
214
871
  };
215
872
  };
216
- /**
217
- * Converts a valid UTC datetime string to JS Date time object.
218
- * By default uses the users local timezone, but an optional
219
- * timezone can be provided.
220
- * Note: This is not meant for time strings
221
- * such as "01:47"
222
- */
223
- const getDateTime = (dateString = '', timeZone = '') => {
224
- /**
225
- * If user passed in undefined
226
- * or null, convert it to the
227
- * empty string since the rest
228
- * of this functions expects
229
- * a string
230
- */
231
- if (dateString === undefined || dateString === null) {
232
- dateString = '';
233
- }
234
- /**
235
- * Ensures that YYYY-MM-DD, YYYY-MM,
236
- * YYYY-DD, YYYY, etc does not get affected
237
- * by timezones and stays on the day/month
238
- * that the user provided
239
- */
240
- if (dateString.length === 10 ||
241
- dateString.length === 7 ||
242
- dateString.length === 4) {
243
- dateString += ' ';
244
- }
245
- const date = (typeof dateString === 'string' && dateString.length > 0) ? new Date(dateString) : new Date();
246
- const localDateTime = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds()));
247
- if (timeZone && timeZone.length > 0) {
248
- return new Date(date.getTime() - getTimezoneOffset(localDateTime, timeZone));
249
- }
250
- return localDateTime;
251
- };
252
- const getTimezoneOffset = (localDate, timeZone) => {
253
- const utcDateTime = new Date(localDate.toLocaleString('en-US', { timeZone: 'utc' }));
254
- const tzDateTime = new Date(localDate.toLocaleString('en-US', { timeZone }));
255
- return utcDateTime.getTime() - tzDateTime.getTime();
256
- };
257
- const updateDate = (existingData, newData, displayTimezone) => {
258
- if (!newData || typeof newData === 'string') {
259
- const dateTime = getDateTime(newData, displayTimezone);
260
- if (!Number.isNaN(dateTime.getTime())) {
261
- newData = dateTime.toISOString();
262
- }
263
- }
264
- if (newData && newData !== '') {
265
- if (typeof newData === 'string') {
266
- // new date is a string, and hopefully in the ISO format
267
- // convert it to our DatetimeData if a valid ISO
268
- newData = parseDate(newData);
269
- if (newData) {
270
- // successfully parsed the ISO string to our DatetimeData
271
- Object.assign(existingData, newData);
272
- return true;
273
- }
274
- }
275
- else if ((newData.year || newData.hour || newData.month || newData.day || newData.minute || newData.second)) {
276
- // newData is from the datetime picker's selected values
277
- // update the existing datetimeValue with the new values
278
- if (newData.ampm !== undefined && newData.hour !== undefined) {
279
- // change the value of the hour based on whether or not it is am or pm
280
- // if the meridiem is pm and equal to 12, it remains 12
281
- // otherwise we add 12 to the hour value
282
- // if the meridiem is am and equal to 12, we change it to 0
283
- // otherwise we use its current hour value
284
- // for example: 8 pm becomes 20, 12 am becomes 0, 4 am becomes 4
285
- newData.hour.value = (newData.ampm.value === 'pm')
286
- ? (newData.hour.value === 12 ? 12 : newData.hour.value + 12)
287
- : (newData.hour.value === 12 ? 0 : newData.hour.value);
288
- }
289
- // merge new values from the picker's selection
290
- // to the existing DatetimeData values
291
- for (const key of Object.keys(newData)) {
292
- existingData[key] = newData[key].value;
293
- }
294
- return true;
295
- }
296
- else if (newData.ampm) {
297
- // Even though in the picker column hour values are between 1 and 12, the hour value is actually normalized
298
- // to [0, 23] interval. Because of this when changing between AM and PM we have to update the hour so it points
299
- // to the correct HH hour
300
- newData.hour = {
301
- value: newData.hour
302
- ? newData.hour.value
303
- : (newData.ampm.value === 'pm'
304
- ? (existingData.hour < 12 ? existingData.hour + 12 : existingData.hour)
305
- : (existingData.hour >= 12 ? existingData.hour - 12 : existingData.hour))
306
- };
307
- existingData['hour'] = newData['hour'].value;
308
- existingData['ampm'] = newData['ampm'].value;
309
- return true;
310
- }
311
- // eww, invalid data
312
- console.warn(`Error parsing date: "${newData}". Please provide a valid ISO 8601 datetime format: https://www.w3.org/TR/NOTE-datetime`);
313
- }
314
- else {
315
- // blank data, clear everything out
316
- for (const k in existingData) {
317
- if (existingData.hasOwnProperty(k)) {
318
- delete existingData[k];
319
- }
320
- }
321
- }
322
- return false;
323
- };
324
- const parseTemplate = (template) => {
325
- const formats = [];
326
- template = template.replace(/[^\w\s]/gi, ' ');
327
- FORMAT_KEYS.forEach(format => {
328
- if (format.f.length > 1 && template.indexOf(format.f) > -1 && template.indexOf(format.f + format.f.charAt(0)) < 0) {
329
- template = template.replace(format.f, ' ' + format.f + ' ');
330
- }
331
- });
332
- const words = template.split(' ').filter(w => w.length > 0);
333
- words.forEach((word, i) => {
334
- FORMAT_KEYS.forEach(format => {
335
- if (word === format.f) {
336
- if (word === FORMAT_A || word === FORMAT_a) {
337
- // this format is an am/pm format, so it's an "a" or "A"
338
- if ((formats.indexOf(FORMAT_h) < 0 && formats.indexOf(FORMAT_hh) < 0) ||
339
- VALID_AMPM_PREFIX.indexOf(words[i - 1]) === -1) {
340
- // template does not already have a 12-hour format
341
- // or this am/pm format doesn't have a hour, minute, or second format immediately before it
342
- // so do not treat this word "a" or "A" as the am/pm format
343
- return;
344
- }
345
- }
346
- formats.push(word);
347
- }
348
- });
349
- });
350
- return formats;
351
- };
352
- const getValueFromFormat = (date, format) => {
353
- if (format === FORMAT_A || format === FORMAT_a) {
354
- return (date.hour < 12 ? 'am' : 'pm');
355
- }
356
- if (format === FORMAT_hh || format === FORMAT_h) {
357
- return (date.hour > 12 ? date.hour - 12 : (date.hour === 0 ? 12 : date.hour));
358
- }
359
- return date[convertFormatToKey(format)];
360
- };
361
- const convertFormatToKey = (format) => {
362
- for (const k in FORMAT_KEYS) {
363
- if (FORMAT_KEYS[k].f === format) {
364
- return FORMAT_KEYS[k].k;
365
- }
366
- }
367
- return undefined;
368
- };
369
- const convertDataToISO = (data) => {
370
- // https://www.w3.org/TR/NOTE-datetime
371
- let rtn = '';
372
- if (data.year !== undefined) {
373
- // YYYY
374
- rtn = fourDigit(data.year);
375
- if (data.month !== undefined) {
376
- // YYYY-MM
377
- rtn += '-' + twoDigit(data.month);
378
- if (data.day !== undefined) {
379
- // YYYY-MM-DD
380
- rtn += '-' + twoDigit(data.day);
381
- if (data.hour !== undefined) {
382
- // YYYY-MM-DDTHH:mm:SS
383
- rtn += `T${twoDigit(data.hour)}:${twoDigit(data.minute)}:${twoDigit(data.second)}`;
384
- if (data.millisecond > 0) {
385
- // YYYY-MM-DDTHH:mm:SS.SSS
386
- rtn += '.' + threeDigit(data.millisecond);
387
- }
388
- if (data.tzOffset === undefined) {
389
- // YYYY-MM-DDTHH:mm:SSZ
390
- rtn += 'Z';
391
- }
392
- else {
393
- // YYYY-MM-DDTHH:mm:SS+/-HH:mm
394
- rtn += (data.tzOffset > 0 ? '+' : '-') + twoDigit(Math.floor(Math.abs(data.tzOffset / 60))) + ':' + twoDigit(data.tzOffset % 60);
395
- }
396
- }
397
- }
398
- }
873
+
874
+ /*!
875
+ * (C) Ionic http://ionicframework.com - MIT License
876
+ */
877
+ const isYearDisabled = (refYear, minParts, maxParts) => {
878
+ if (minParts && minParts.year > refYear) {
879
+ return true;
399
880
  }
400
- else if (data.hour !== undefined) {
401
- // HH:mm
402
- rtn = twoDigit(data.hour) + ':' + twoDigit(data.minute);
403
- if (data.second !== undefined) {
404
- // HH:mm:SS
405
- rtn += ':' + twoDigit(data.second);
406
- if (data.millisecond !== undefined) {
407
- // HH:mm:SS.SSS
408
- rtn += '.' + threeDigit(data.millisecond);
409
- }
410
- }
881
+ if (maxParts && maxParts.year < refYear) {
882
+ return true;
411
883
  }
412
- return rtn;
884
+ return false;
413
885
  };
414
886
  /**
415
- * Use to convert a string of comma separated strings or
416
- * an array of strings, and clean up any user input
887
+ * Returns true if a given day should
888
+ * not be interactive according to its value,
889
+ * or the max/min dates.
417
890
  */
418
- const convertToArrayOfStrings = (input, type) => {
419
- if (input == null) {
420
- return undefined;
891
+ const isDayDisabled = (refParts, minParts, maxParts, dayValues) => {
892
+ /**
893
+ * If this is a filler date (i.e. padding)
894
+ * then the date is disabled.
895
+ */
896
+ if (refParts.day === null) {
897
+ return true;
421
898
  }
422
- if (typeof input === 'string') {
423
- // convert the string to an array of strings
424
- // auto remove any [] characters
425
- input = input.replace(/\[|\]/g, '').split(',');
899
+ /**
900
+ * If user passed in a list of acceptable day values
901
+ * check to make sure that the date we are looking
902
+ * at is in this array.
903
+ */
904
+ if (dayValues !== undefined && !dayValues.includes(refParts.day)) {
905
+ return true;
426
906
  }
427
- let values;
428
- if (Array.isArray(input)) {
429
- // trim up each string value
430
- values = input.map(val => val.toString().trim());
907
+ /**
908
+ * Given a min date, perform the following
909
+ * checks. If any of them are true, then the
910
+ * day should be disabled:
911
+ * 1. Is the current year < the min allowed year?
912
+ * 2. Is the current year === min allowed year,
913
+ * but the current month < the min allowed month?
914
+ * 3. Is the current year === min allowed year, the
915
+ * current month === min allow month, but the current
916
+ * day < the min allowed day?
917
+ */
918
+ if (minParts && isBefore(refParts, minParts)) {
919
+ return true;
431
920
  }
432
- if (values === undefined || values.length === 0) {
433
- console.warn(`Invalid "${type}Names". Must be an array of strings, or a comma separated string.`);
921
+ /**
922
+ * Given a max date, perform the following
923
+ * checks. If any of them are true, then the
924
+ * day should be disabled:
925
+ * 1. Is the current year > the max allowed year?
926
+ * 2. Is the current year === max allowed year,
927
+ * but the current month > the max allowed month?
928
+ * 3. Is the current year === max allowed year, the
929
+ * current month === max allow month, but the current
930
+ * day > the max allowed day?
931
+ */
932
+ if (maxParts && isAfter(refParts, maxParts)) {
933
+ return true;
434
934
  }
435
- return values;
935
+ /**
936
+ * If none of these checks
937
+ * passed then the date should
938
+ * be interactive.
939
+ */
940
+ return false;
436
941
  };
437
942
  /**
438
- * Use to convert a string of comma separated numbers or
439
- * an array of numbers, and clean up any user input
943
+ * Given a locale, a date, the selected date, and today's date,
944
+ * generate the state for a given calendar day button.
440
945
  */
441
- const convertToArrayOfNumbers = (input, type) => {
442
- if (typeof input === 'string') {
443
- // convert the string to an array of strings
444
- // auto remove any whitespace and [] characters
445
- input = input.replace(/\[|\]|\s/g, '').split(',');
446
- }
447
- let values;
448
- if (Array.isArray(input)) {
449
- // ensure each value is an actual number in the returned array
450
- values = input
451
- .map((num) => parseInt(num, 10))
452
- .filter(isFinite);
453
- }
454
- else {
455
- values = [input];
946
+ const getCalendarDayState = (locale, refParts, activeParts, todayParts, minParts, maxParts, dayValues) => {
947
+ const isActive = isSameDay(refParts, activeParts);
948
+ const isToday = isSameDay(refParts, todayParts);
949
+ const disabled = isDayDisabled(refParts, minParts, maxParts, dayValues);
950
+ return {
951
+ disabled,
952
+ isActive,
953
+ isToday,
954
+ ariaSelected: isActive ? 'true' : null,
955
+ ariaLabel: generateDayAriaLabel(locale, isToday, refParts)
956
+ };
957
+ };
958
+ /**
959
+ * Returns `true` if the month is disabled given the
960
+ * current date value and min/max date constraints.
961
+ */
962
+ const isMonthDisabled = (refParts, { minParts, maxParts }) => {
963
+ // If the year is disabled then the month is disabled.
964
+ if (isYearDisabled(refParts.year, minParts, maxParts)) {
965
+ return true;
456
966
  }
457
- if (values.length === 0) {
458
- console.warn(`Invalid "${type}Values". Must be an array of numbers, or a comma separated string of numbers.`);
967
+ // If the date value is before the min date, then the month is disabled.
968
+ // If the date value is after the max date, then the month is disabled.
969
+ if (minParts && isBefore(refParts, minParts) || maxParts && isAfter(refParts, maxParts)) {
970
+ return true;
459
971
  }
460
- return values;
461
- };
462
- const twoDigit = (val) => {
463
- return ('0' + (val !== undefined ? Math.abs(val) : '0')).slice(-2);
972
+ return false;
464
973
  };
465
- const threeDigit = (val) => {
466
- return ('00' + (val !== undefined ? Math.abs(val) : '0')).slice(-3);
974
+ /**
975
+ * Given a working date, an optional minimum date range,
976
+ * and an optional maximum date range; determine if the
977
+ * previous navigation button is disabled.
978
+ */
979
+ const isPrevMonthDisabled = (refParts, minParts, maxParts) => {
980
+ const prevMonth = getPreviousMonth(refParts);
981
+ return isMonthDisabled(prevMonth, {
982
+ minParts,
983
+ maxParts
984
+ });
467
985
  };
468
- const fourDigit = (val) => {
469
- return ('000' + (val !== undefined ? Math.abs(val) : '0')).slice(-4);
986
+ /**
987
+ * Given a working date and a maximum date range,
988
+ * determine if the next navigation button is disabled.
989
+ */
990
+ const isNextMonthDisabled = (refParts, maxParts) => {
991
+ const nextMonth = getNextMonth(refParts);
992
+ return isMonthDisabled(nextMonth, {
993
+ maxParts
994
+ });
470
995
  };
471
- const FORMAT_YYYY = 'YYYY';
472
- const FORMAT_YY = 'YY';
473
- const FORMAT_MMMM = 'MMMM';
474
- const FORMAT_MMM = 'MMM';
475
- const FORMAT_MM = 'MM';
476
- const FORMAT_M = 'M';
477
- const FORMAT_DDDD = 'DDDD';
478
- const FORMAT_DDD = 'DDD';
479
- const FORMAT_DD = 'DD';
480
- const FORMAT_D = 'D';
481
- const FORMAT_HH = 'HH';
482
- const FORMAT_H = 'H';
483
- const FORMAT_hh = 'hh';
484
- const FORMAT_h = 'h';
485
- const FORMAT_mm = 'mm';
486
- const FORMAT_m = 'm';
487
- const FORMAT_ss = 'ss';
488
- const FORMAT_s = 's';
489
- const FORMAT_A = 'A';
490
- const FORMAT_a = 'a';
491
- const FORMAT_KEYS = [
492
- { f: FORMAT_YYYY, k: 'year' },
493
- { f: FORMAT_MMMM, k: 'month' },
494
- { f: FORMAT_DDDD, k: 'day' },
495
- { f: FORMAT_MMM, k: 'month' },
496
- { f: FORMAT_DDD, k: 'day' },
497
- { f: FORMAT_YY, k: 'year' },
498
- { f: FORMAT_MM, k: 'month' },
499
- { f: FORMAT_DD, k: 'day' },
500
- { f: FORMAT_HH, k: 'hour' },
501
- { f: FORMAT_hh, k: 'hour' },
502
- { f: FORMAT_mm, k: 'minute' },
503
- { f: FORMAT_ss, k: 'second' },
504
- { f: FORMAT_M, k: 'month' },
505
- { f: FORMAT_D, k: 'day' },
506
- { f: FORMAT_H, k: 'hour' },
507
- { f: FORMAT_h, k: 'hour' },
508
- { f: FORMAT_m, k: 'minute' },
509
- { f: FORMAT_s, k: 'second' },
510
- { f: FORMAT_A, k: 'ampm' },
511
- { f: FORMAT_a, k: 'ampm' },
512
- ];
513
- const DAY_NAMES = [
514
- 'Sunday',
515
- 'Monday',
516
- 'Tuesday',
517
- 'Wednesday',
518
- 'Thursday',
519
- 'Friday',
520
- 'Saturday',
521
- ];
522
- const DAY_SHORT_NAMES = [
523
- 'Sun',
524
- 'Mon',
525
- 'Tue',
526
- 'Wed',
527
- 'Thu',
528
- 'Fri',
529
- 'Sat',
530
- ];
531
- const MONTH_NAMES = [
532
- 'January',
533
- 'February',
534
- 'March',
535
- 'April',
536
- 'May',
537
- 'June',
538
- 'July',
539
- 'August',
540
- 'September',
541
- 'October',
542
- 'November',
543
- 'December',
544
- ];
545
- const MONTH_SHORT_NAMES = [
546
- 'Jan',
547
- 'Feb',
548
- 'Mar',
549
- 'Apr',
550
- 'May',
551
- 'Jun',
552
- 'Jul',
553
- 'Aug',
554
- 'Sep',
555
- 'Oct',
556
- 'Nov',
557
- 'Dec',
558
- ];
559
- const VALID_AMPM_PREFIX = [
560
- FORMAT_hh, FORMAT_h, FORMAT_mm, FORMAT_m, FORMAT_ss, FORMAT_s
561
- ];
562
996
 
563
- const datetimeIosCss = ":host{padding-left:var(--padding-start);padding-right:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);display:flex;position:relative;min-width:16px;min-height:1.2em;font-family:var(--ion-font-family, inherit);text-overflow:ellipsis;white-space:nowrap;overflow:hidden;z-index:2}@supports (margin-inline-start: 0) or (-webkit-margin-start: 0){:host{padding-left:unset;padding-right:unset;-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end)}}:host(.in-item){position:static}:host(.datetime-placeholder){color:var(--placeholder-color)}:host(.datetime-disabled){opacity:0.3;pointer-events:none}:host(.datetime-readonly){pointer-events:none}button{left:0;top:0;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;position:absolute;width:100%;height:100%;border:0;background:transparent;cursor:pointer;appearance:none;outline:none}[dir=rtl] button,:host-context([dir=rtl]) button{left:unset;right:unset;right:0}button::-moz-focus-inner{border:0}.datetime-text{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;flex:1;min-height:inherit;direction:ltr;overflow:inherit}[dir=rtl] .datetime-text,:host-context([dir=rtl]) .datetime-text{direction:rtl}:host{--placeholder-color:var(--ion-color-step-400, #999999);--padding-top:10px;--padding-end:10px;--padding-bottom:10px;--padding-start:20px}";
997
+ const datetimeIosCss = ":host{display:flex;flex-flow:column;background:var(--background);overflow:hidden}:host(.datetime-size-fixed){width:auto;max-width:350px;height:auto}:host(.datetime-size-cover){width:100%}:host .calendar-body,:host .datetime-year{opacity:0}:host(:not(.datetime-ready)) .datetime-year{position:absolute;pointer-events:none}:host(.datetime-ready) .calendar-body{opacity:1}:host(.datetime-ready) .datetime-year{display:none;opacity:1}:host .datetime-year .order-month-first .month-column{order:1}:host .datetime-year .order-month-first .year-column{order:2}:host .datetime-year .order-year-first .month-column{order:2;text-align:end}:host .datetime-year .order-year-first .year-column{order:1;text-align:start}:host .datetime-calendar,:host .datetime-year{display:flex;flex:1 1 auto;flex-flow:column}:host(.show-month-and-year) .datetime-year{display:flex}@supports (background: -webkit-named-image(apple-pay-logo-black)) and (not (aspect-ratio: 1/1)){:host(.show-month-and-year) .calendar-next-prev,:host(.show-month-and-year) .calendar-days-of-week,:host(.show-month-and-year) .calendar-body,:host(.show-month-and-year) .datetime-time{left:-99999px;position:absolute;visibility:hidden;pointer-events:none}:host-context([dir=rtl]):host(.show-month-and-year) .calendar-next-prev,:host-context([dir=rtl]).show-month-and-year .calendar-next-prev,:host-context([dir=rtl]):host(.show-month-and-year) .calendar-days-of-week,:host-context([dir=rtl]).show-month-and-year .calendar-days-of-week,:host-context([dir=rtl]):host(.show-month-and-year) .calendar-body,:host-context([dir=rtl]).show-month-and-year .calendar-body,:host-context([dir=rtl]):host(.show-month-and-year) .datetime-time,:host-context([dir=rtl]).show-month-and-year .datetime-time{left:unset;right:unset;right:-99999px}}@supports (not (background: -webkit-named-image(apple-pay-logo-black))) or ((background: -webkit-named-image(apple-pay-logo-black)) and (aspect-ratio: 1/1)){:host(.show-month-and-year) .calendar-next-prev,:host(.show-month-and-year) .calendar-days-of-week,:host(.show-month-and-year) .calendar-body,:host(.show-month-and-year) .datetime-time{display:none}}:host(.datetime-readonly),:host(.datetime-disabled){pointer-events:none}:host(.datetime-disabled){opacity:0.4}:host .datetime-header .datetime-title{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}:host .datetime-action-buttons.has-clear-button{width:100%}:host .datetime-action-buttons ion-buttons{display:flex;justify-content:space-between}:host .calendar-action-buttons{display:flex;justify-content:space-between}:host .calendar-action-buttons ion-item,:host .calendar-action-buttons ion-button{--background:translucent}:host .calendar-action-buttons ion-item ion-label{display:flex;align-items:center}:host .calendar-action-buttons ion-item ion-icon{padding-left:4px;padding-right:0;padding-top:0;padding-bottom:0}@supports (margin-inline-start: 0) or (-webkit-margin-start: 0){:host .calendar-action-buttons ion-item ion-icon{padding-left:unset;padding-right:unset;-webkit-padding-start:4px;padding-inline-start:4px;-webkit-padding-end:0;padding-inline-end:0}}:host .calendar-days-of-week{display:grid;grid-template-columns:repeat(7, 1fr);text-align:center}:host .calendar-body{display:flex;flex-grow:1;scroll-snap-type:x mandatory;overflow-x:scroll;overflow-y:hidden;scrollbar-width:none;outline:none}:host .calendar-body .calendar-month{scroll-snap-align:start;scroll-snap-stop:always;flex-shrink:0;width:100%}:host .calendar-body .calendar-month-disabled{scroll-snap-align:none}:host .calendar-body::-webkit-scrollbar{display:none}:host .calendar-body .calendar-month-grid{display:grid;grid-template-columns:repeat(7, 1fr);height:100%}:host .calendar-day{padding-left:0px;padding-right:0px;padding-top:0px;padding-bottom:0px;margin-left:0px;margin-right:0px;margin-top:0px;margin-bottom:0px;display:flex;position:relative;align-items:center;justify-content:center;border:none;outline:none;background:none;color:currentColor;cursor:pointer;appearance:none;z-index:0}@supports (margin-inline-start: 0) or (-webkit-margin-start: 0){:host .calendar-day{padding-left:unset;padding-right:unset;-webkit-padding-start:0px;padding-inline-start:0px;-webkit-padding-end:0px;padding-inline-end:0px}}@supports (margin-inline-start: 0) or (-webkit-margin-start: 0){:host .calendar-day{margin-left:unset;margin-right:unset;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px}}:host .calendar-day[disabled]{pointer-events:none;opacity:0.4}:host .calendar-day:after{border-radius:32px;padding-left:4px;padding-right:4px;padding-top:4px;padding-bottom:4px;left:50%;top:50%;position:absolute;width:32px;height:32px;transform:translate(-50%, -50%);content:\" \";z-index:-1}@supports (margin-inline-start: 0) or (-webkit-margin-start: 0){:host .calendar-day:after{padding-left:unset;padding-right:unset;-webkit-padding-start:4px;padding-inline-start:4px;-webkit-padding-end:4px;padding-inline-end:4px}}:host-context([dir=rtl]){left:unset;right:unset;right:50%}:host .datetime-time{display:flex;justify-content:space-between}:host(.datetime-presentation-time) .datetime-time{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0}:host ion-popover{--height:200px}:host .time-header{display:flex;align-items:center}:host .time-body{border-radius:8px;padding-left:12px;padding-right:12px;padding-top:6px;padding-bottom:6px;display:flex;border:none;background:var(--ion-color-step-300, #edeef0);color:var(--ion-text-color, #000);font-family:inherit;font-size:inherit;cursor:pointer;appearance:none}@supports (margin-inline-start: 0) or (-webkit-margin-start: 0){:host .time-body{padding-left:unset;padding-right:unset;-webkit-padding-start:12px;padding-inline-start:12px;-webkit-padding-end:12px;padding-inline-end:12px}}:host .time-body-active{color:var(--ion-color-base)}:host(.in-item){position:static}:host(.show-month-and-year) .calendar-action-buttons ion-item{--color:var(--ion-color-base)}:host{--background:var(--ion-color-light, #ffffff);--background-rgb:var(--ion-color-light-rgb);--title-color:var(--ion-color-step-600, #666666)}:host(.datetime-presentation-date-time),:host(.datetime-presentation-time-date),:host(.datetime-presentation-date){min-height:350px}:host .datetime-header{padding-left:16px;padding-right:16px;padding-top:16px;padding-bottom:16px;border-bottom:0.55px solid var(--ion-color-step-200, #cccccc)}@supports (margin-inline-start: 0) or (-webkit-margin-start: 0){:host .datetime-header{padding-left:unset;padding-right:unset;-webkit-padding-start:16px;padding-inline-start:16px;-webkit-padding-end:16px;padding-inline-end:16px}}:host .datetime-header .datetime-title{color:var(--title-color);font-size:14px}:host .calendar-action-buttons ion-item{--padding-start:16px;--background-hover:transparent;--background-activated:transparent;font-size:16px;font-weight:600}:host .calendar-action-buttons ion-item ion-icon,:host .calendar-action-buttons ion-buttons ion-button{color:var(--ion-color-base)}:host .calendar-action-buttons ion-buttons{padding-left:0;padding-right:0;padding-top:8px;padding-bottom:0}:host .calendar-action-buttons ion-buttons ion-button{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0}:host .calendar-days-of-week{padding-left:8px;padding-right:8px;padding-top:0;padding-bottom:0;color:var(--ion-color-step-300, #b3b3b3);font-size:12px;font-weight:600;line-height:24px;text-transform:uppercase}@supports (margin-inline-start: 0) or (-webkit-margin-start: 0){:host .calendar-days-of-week{padding-left:unset;padding-right:unset;-webkit-padding-start:8px;padding-inline-start:8px;-webkit-padding-end:8px;padding-inline-end:8px}}:host .calendar-body .calendar-month .calendar-month-grid{padding-left:8px;padding-right:8px;padding-top:8px;padding-bottom:8px;height:calc(100% - 16px)}@supports (margin-inline-start: 0) or (-webkit-margin-start: 0){:host .calendar-body .calendar-month .calendar-month-grid{padding-left:unset;padding-right:unset;-webkit-padding-start:8px;padding-inline-start:8px;-webkit-padding-end:8px;padding-inline-end:8px}}:host .calendar-day{font-size:20px}:host .calendar-day:after{opacity:0.2}:host .calendar-day:focus:after{background:var(--ion-color-base)}:host .calendar-day.calendar-day-today{color:var(--ion-color-base)}:host .calendar-day.calendar-day-active{color:var(--ion-color-base);font-weight:600}:host .calendar-day.calendar-day-active:after{background:var(--ion-color-base)}:host .calendar-day.calendar-day-today.calendar-day-active{color:var(--ion-color-contrast)}:host .calendar-day.calendar-day-today.calendar-day-active:after{background:var(--ion-color-base);opacity:1}:host .datetime-time{padding-left:16px;padding-right:16px;padding-top:8px;padding-bottom:16px;font-size:16px}@supports (margin-inline-start: 0) or (-webkit-margin-start: 0){:host .datetime-time{padding-left:unset;padding-right:unset;-webkit-padding-start:16px;padding-inline-start:16px;-webkit-padding-end:16px;padding-inline-end:16px}}:host .datetime-time .time-header{font-weight:600}:host .datetime-buttons{padding-left:8px;padding-right:8px;padding-top:8px;padding-bottom:8px;border-top:0.55px solid var(--ion-color-step-200, #cccccc)}@supports (margin-inline-start: 0) or (-webkit-margin-start: 0){:host .datetime-buttons{padding-left:unset;padding-right:unset;-webkit-padding-start:8px;padding-inline-start:8px;-webkit-padding-end:8px;padding-inline-end:8px}}:host .datetime-buttons ::slotted(ion-buttons),:host .datetime-buttons ion-buttons{display:flex;align-items:center;justify-content:space-between}:host .datetime-action-buttons{width:100%}";
564
998
 
565
- const datetimeMdCss = ":host{padding-left:var(--padding-start);padding-right:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);display:flex;position:relative;min-width:16px;min-height:1.2em;font-family:var(--ion-font-family, inherit);text-overflow:ellipsis;white-space:nowrap;overflow:hidden;z-index:2}@supports (margin-inline-start: 0) or (-webkit-margin-start: 0){:host{padding-left:unset;padding-right:unset;-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end)}}:host(.in-item){position:static}:host(.datetime-placeholder){color:var(--placeholder-color)}:host(.datetime-disabled){opacity:0.3;pointer-events:none}:host(.datetime-readonly){pointer-events:none}button{left:0;top:0;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;position:absolute;width:100%;height:100%;border:0;background:transparent;cursor:pointer;appearance:none;outline:none}[dir=rtl] button,:host-context([dir=rtl]) button{left:unset;right:unset;right:0}button::-moz-focus-inner{border:0}.datetime-text{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;flex:1;min-height:inherit;direction:ltr;overflow:inherit}[dir=rtl] .datetime-text,:host-context([dir=rtl]) .datetime-text{direction:rtl}:host{--placeholder-color:var(--ion-placeholder-color, var(--ion-color-step-400, #999999));--padding-top:10px;--padding-end:0;--padding-bottom:11px;--padding-start:16px}";
999
+ const datetimeMdCss = ":host{display:flex;flex-flow:column;background:var(--background);overflow:hidden}:host(.datetime-size-fixed){width:auto;max-width:350px;height:auto}:host(.datetime-size-cover){width:100%}:host .calendar-body,:host .datetime-year{opacity:0}:host(:not(.datetime-ready)) .datetime-year{position:absolute;pointer-events:none}:host(.datetime-ready) .calendar-body{opacity:1}:host(.datetime-ready) .datetime-year{display:none;opacity:1}:host .datetime-year .order-month-first .month-column{order:1}:host .datetime-year .order-month-first .year-column{order:2}:host .datetime-year .order-year-first .month-column{order:2;text-align:end}:host .datetime-year .order-year-first .year-column{order:1;text-align:start}:host .datetime-calendar,:host .datetime-year{display:flex;flex:1 1 auto;flex-flow:column}:host(.show-month-and-year) .datetime-year{display:flex}@supports (background: -webkit-named-image(apple-pay-logo-black)) and (not (aspect-ratio: 1/1)){:host(.show-month-and-year) .calendar-next-prev,:host(.show-month-and-year) .calendar-days-of-week,:host(.show-month-and-year) .calendar-body,:host(.show-month-and-year) .datetime-time{left:-99999px;position:absolute;visibility:hidden;pointer-events:none}:host-context([dir=rtl]):host(.show-month-and-year) .calendar-next-prev,:host-context([dir=rtl]).show-month-and-year .calendar-next-prev,:host-context([dir=rtl]):host(.show-month-and-year) .calendar-days-of-week,:host-context([dir=rtl]).show-month-and-year .calendar-days-of-week,:host-context([dir=rtl]):host(.show-month-and-year) .calendar-body,:host-context([dir=rtl]).show-month-and-year .calendar-body,:host-context([dir=rtl]):host(.show-month-and-year) .datetime-time,:host-context([dir=rtl]).show-month-and-year .datetime-time{left:unset;right:unset;right:-99999px}}@supports (not (background: -webkit-named-image(apple-pay-logo-black))) or ((background: -webkit-named-image(apple-pay-logo-black)) and (aspect-ratio: 1/1)){:host(.show-month-and-year) .calendar-next-prev,:host(.show-month-and-year) .calendar-days-of-week,:host(.show-month-and-year) .calendar-body,:host(.show-month-and-year) .datetime-time{display:none}}:host(.datetime-readonly),:host(.datetime-disabled){pointer-events:none}:host(.datetime-disabled){opacity:0.4}:host .datetime-header .datetime-title{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}:host .datetime-action-buttons.has-clear-button{width:100%}:host .datetime-action-buttons ion-buttons{display:flex;justify-content:space-between}:host .calendar-action-buttons{display:flex;justify-content:space-between}:host .calendar-action-buttons ion-item,:host .calendar-action-buttons ion-button{--background:translucent}:host .calendar-action-buttons ion-item ion-label{display:flex;align-items:center}:host .calendar-action-buttons ion-item ion-icon{padding-left:4px;padding-right:0;padding-top:0;padding-bottom:0}@supports (margin-inline-start: 0) or (-webkit-margin-start: 0){:host .calendar-action-buttons ion-item ion-icon{padding-left:unset;padding-right:unset;-webkit-padding-start:4px;padding-inline-start:4px;-webkit-padding-end:0;padding-inline-end:0}}:host .calendar-days-of-week{display:grid;grid-template-columns:repeat(7, 1fr);text-align:center}:host .calendar-body{display:flex;flex-grow:1;scroll-snap-type:x mandatory;overflow-x:scroll;overflow-y:hidden;scrollbar-width:none;outline:none}:host .calendar-body .calendar-month{scroll-snap-align:start;scroll-snap-stop:always;flex-shrink:0;width:100%}:host .calendar-body .calendar-month-disabled{scroll-snap-align:none}:host .calendar-body::-webkit-scrollbar{display:none}:host .calendar-body .calendar-month-grid{display:grid;grid-template-columns:repeat(7, 1fr);height:100%}:host .calendar-day{padding-left:0px;padding-right:0px;padding-top:0px;padding-bottom:0px;margin-left:0px;margin-right:0px;margin-top:0px;margin-bottom:0px;display:flex;position:relative;align-items:center;justify-content:center;border:none;outline:none;background:none;color:currentColor;cursor:pointer;appearance:none;z-index:0}@supports (margin-inline-start: 0) or (-webkit-margin-start: 0){:host .calendar-day{padding-left:unset;padding-right:unset;-webkit-padding-start:0px;padding-inline-start:0px;-webkit-padding-end:0px;padding-inline-end:0px}}@supports (margin-inline-start: 0) or (-webkit-margin-start: 0){:host .calendar-day{margin-left:unset;margin-right:unset;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px}}:host .calendar-day[disabled]{pointer-events:none;opacity:0.4}:host .calendar-day:after{border-radius:32px;padding-left:4px;padding-right:4px;padding-top:4px;padding-bottom:4px;left:50%;top:50%;position:absolute;width:32px;height:32px;transform:translate(-50%, -50%);content:\" \";z-index:-1}@supports (margin-inline-start: 0) or (-webkit-margin-start: 0){:host .calendar-day:after{padding-left:unset;padding-right:unset;-webkit-padding-start:4px;padding-inline-start:4px;-webkit-padding-end:4px;padding-inline-end:4px}}:host-context([dir=rtl]){left:unset;right:unset;right:50%}:host .datetime-time{display:flex;justify-content:space-between}:host(.datetime-presentation-time) .datetime-time{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0}:host ion-popover{--height:200px}:host .time-header{display:flex;align-items:center}:host .time-body{border-radius:8px;padding-left:12px;padding-right:12px;padding-top:6px;padding-bottom:6px;display:flex;border:none;background:var(--ion-color-step-300, #edeef0);color:var(--ion-text-color, #000);font-family:inherit;font-size:inherit;cursor:pointer;appearance:none}@supports (margin-inline-start: 0) or (-webkit-margin-start: 0){:host .time-body{padding-left:unset;padding-right:unset;-webkit-padding-start:12px;padding-inline-start:12px;-webkit-padding-end:12px;padding-inline-end:12px}}:host .time-body-active{color:var(--ion-color-base)}:host(.in-item){position:static}:host(.show-month-and-year) .calendar-action-buttons ion-item{--color:var(--ion-color-base)}:host{--background:var(--ion-color-step-100, #ffffff);--title-color:var(--ion-color-contrast)}:host .datetime-header{padding-left:20px;padding-right:20px;padding-top:20px;padding-bottom:20px;background:var(--ion-color-base);color:var(--title-color)}@supports (margin-inline-start: 0) or (-webkit-margin-start: 0){:host .datetime-header{padding-left:unset;padding-right:unset;-webkit-padding-start:20px;padding-inline-start:20px;-webkit-padding-end:20px;padding-inline-end:20px}}:host .datetime-header .datetime-title{font-size:12px;text-transform:uppercase}:host .datetime-header .datetime-selected-date{margin-top:30px;font-size:34px}:host .datetime-calendar .calendar-action-buttons ion-item{--padding-start:20px}:host .calendar-action-buttons ion-item,:host .calendar-action-buttons ion-button{color:var(--ion-color-step-650, #595959)}:host .calendar-days-of-week{padding-left:10px;padding-right:10px;padding-top:0px;padding-bottom:0px;color:var(--ion-color-step-500, gray);font-size:14px;line-height:36px}@supports (margin-inline-start: 0) or (-webkit-margin-start: 0){:host .calendar-days-of-week{padding-left:unset;padding-right:unset;-webkit-padding-start:10px;padding-inline-start:10px;-webkit-padding-end:10px;padding-inline-end:10px}}:host .calendar-body .calendar-month .calendar-month-grid{padding-left:10px;padding-right:10px;padding-top:3px;padding-bottom:0px;grid-template-rows:repeat(6, 1fr)}@supports (margin-inline-start: 0) or (-webkit-margin-start: 0){:host .calendar-body .calendar-month .calendar-month-grid{padding-left:unset;padding-right:unset;-webkit-padding-start:10px;padding-inline-start:10px;-webkit-padding-end:10px;padding-inline-end:10px}}:host .calendar-day{padding-left:0px;padding-right:0;padding-top:13px;padding-bottom:13px;font-size:14px}@supports (margin-inline-start: 0) or (-webkit-margin-start: 0){:host .calendar-day{padding-left:unset;padding-right:unset;-webkit-padding-start:0px;padding-inline-start:0px;-webkit-padding-end:0;padding-inline-end:0}}:host .calendar-day:focus:after{background:rgba(var(--ion-color-base-rgb), 0.2);box-shadow:0px 0px 0px 4px rgba(var(--ion-color-base-rgb), 0.2)}:host .calendar-day.calendar-day-today{color:var(--ion-color-base)}:host .calendar-day.calendar-day-today:after{border:1px solid var(--ion-color-base)}:host .calendar-day.calendar-day-active{color:var(--ion-color-contrast)}:host .calendar-day.calendar-day-active:after{border:1px solid var(--ion-color-base);background:var(--ion-color-base)}:host .datetime-time{padding-left:16px;padding-right:16px;padding-top:8px;padding-bottom:8px}@supports (margin-inline-start: 0) or (-webkit-margin-start: 0){:host .datetime-time{padding-left:unset;padding-right:unset;-webkit-padding-start:16px;padding-inline-start:16px;-webkit-padding-end:16px;padding-inline-end:16px}}:host .time-header{color:var(--ion-color-step-650, #595959)}:host(.datetime-presentation-month) .datetime-year,:host(.datetime-presentation-year) .datetime-year,:host(.datetime-presentation-month-year) .datetime-year{margin-top:20px;margin-bottom:20px}:host .datetime-buttons{padding-left:10px;padding-right:10px;padding-top:10px;padding-bottom:10px;display:flex;align-items:center;justify-content:flex-end}@supports (margin-inline-start: 0) or (-webkit-margin-start: 0){:host .datetime-buttons{padding-left:unset;padding-right:unset;-webkit-padding-start:10px;padding-inline-start:10px;-webkit-padding-end:10px;padding-inline-end:10px}}:host .datetime-view-buttons ion-button{color:var(--ion-color-step-800, #333333)}";
566
1000
 
567
1001
  const Datetime = class {
568
1002
  constructor(hostRef) {
@@ -573,11 +1007,34 @@ const Datetime = class {
573
1007
  this.ionBlur = createEvent(this, "ionBlur", 7);
574
1008
  this.ionStyle = createEvent(this, "ionStyle", 7);
575
1009
  this.inputId = `ion-dt-${datetimeIds++}`;
576
- this.locale = {};
577
- this.datetimeMin = {};
578
- this.datetimeMax = {};
579
- this.datetimeValue = {};
580
- this.isExpanded = false;
1010
+ this.overlayIsPresenting = false;
1011
+ this.todayParts = parseDate(getToday());
1012
+ this.prevPresentation = null;
1013
+ this.showMonthAndYear = false;
1014
+ this.activeParts = {
1015
+ month: 5,
1016
+ day: 28,
1017
+ year: 2021,
1018
+ hour: 13,
1019
+ minute: 52,
1020
+ ampm: 'pm'
1021
+ };
1022
+ this.workingParts = {
1023
+ month: 5,
1024
+ day: 28,
1025
+ year: 2021,
1026
+ hour: 13,
1027
+ minute: 52,
1028
+ ampm: 'pm'
1029
+ };
1030
+ this.isPresented = false;
1031
+ this.isTimePopoverOpen = false;
1032
+ /**
1033
+ * The color to use from your application's color palette.
1034
+ * Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`.
1035
+ * For more information on colors, see [theming](/docs/theming/basics).
1036
+ */
1037
+ this.color = 'primary';
581
1038
  /**
582
1039
  * The name of the control, which is submitted with the form data.
583
1040
  */
@@ -591,13 +1048,13 @@ const Datetime = class {
591
1048
  */
592
1049
  this.readonly = false;
593
1050
  /**
594
- * The display format of the date and time as text that shows
595
- * within the item. When the `pickerFormat` input is not used, then the
596
- * `displayFormat` is used for both display the formatted text, and determining
597
- * the datetime picker's columns. See the `pickerFormat` input description for
598
- * more info. Defaults to `MMM D, YYYY`.
1051
+ * Which values you want to select. `'date'` will show
1052
+ * a calendar picker to select the month, day, and year. `'time'`
1053
+ * will show a time picker to select the hour, minute, and (optionally)
1054
+ * AM/PM. `'date-time'` will show the date picker first and time picker second.
1055
+ * `'time-date'` will show the time picker first and date picker second.
599
1056
  */
600
- this.displayFormat = 'MMM D, YYYY';
1057
+ this.presentation = 'date-time';
601
1058
  /**
602
1059
  * The text to display on the picker's cancel button.
603
1060
  */
@@ -606,9 +1063,474 @@ const Datetime = class {
606
1063
  * The text to display on the picker's "Done" button.
607
1064
  */
608
1065
  this.doneText = 'Done';
609
- this.onClick = () => {
610
- this.setFocus();
611
- this.open();
1066
+ /**
1067
+ * The text to display on the picker's "Clear" button.
1068
+ */
1069
+ this.clearText = 'Clear';
1070
+ /**
1071
+ * The locale to use for `ion-datetime`. This
1072
+ * impacts month and day name formatting.
1073
+ * The `'default'` value refers to the default
1074
+ * locale set by your device.
1075
+ */
1076
+ this.locale = 'default';
1077
+ /**
1078
+ * The first day of the week to use for `ion-datetime`. The
1079
+ * default value is `0` and represents Sunday.
1080
+ */
1081
+ this.firstDayOfWeek = 0;
1082
+ /**
1083
+ * If `true`, a header will be shown above the calendar
1084
+ * picker. On `ios` mode this will include the
1085
+ * slotted title, and on `md` mode this will include
1086
+ * the slotted title and the selected date.
1087
+ */
1088
+ this.showDefaultTitle = false;
1089
+ /**
1090
+ * If `true`, the default "Cancel" and "OK" buttons
1091
+ * will be rendered at the bottom of the `ion-datetime`
1092
+ * component. Developers can also use the `button` slot
1093
+ * if they want to customize these buttons. If custom
1094
+ * buttons are set in the `button` slot then the
1095
+ * default buttons will not be rendered.
1096
+ */
1097
+ this.showDefaultButtons = false;
1098
+ /**
1099
+ * If `true`, a "Clear" button will be rendered alongside
1100
+ * the default "Cancel" and "OK" buttons at the bottom of the `ion-datetime`
1101
+ * component. Developers can also use the `button` slot
1102
+ * if they want to customize these buttons. If custom
1103
+ * buttons are set in the `button` slot then the
1104
+ * default buttons will not be rendered.
1105
+ */
1106
+ this.showClearButton = false;
1107
+ /**
1108
+ * If `true`, the default "Time" label will be rendered
1109
+ * for the time selector of the `ion-datetime` component.
1110
+ * Developers can also use the `time-label` slot
1111
+ * if they want to customize this label. If a custom
1112
+ * label is set in the `time-label` slot then the
1113
+ * default label will not be rendered.
1114
+ */
1115
+ this.showDefaultTimeLabel = true;
1116
+ /**
1117
+ * If `cover`, the `ion-datetime` will expand to cover the full width of its container.
1118
+ * If `fixed`, the `ion-datetime` will have a fixed width.
1119
+ */
1120
+ this.size = 'fixed';
1121
+ this.closeParentOverlay = () => {
1122
+ const popoverOrModal = this.el.closest('ion-modal, ion-popover');
1123
+ if (popoverOrModal) {
1124
+ popoverOrModal.dismiss();
1125
+ }
1126
+ };
1127
+ this.setWorkingParts = (parts) => {
1128
+ this.workingParts = Object.assign({}, parts);
1129
+ };
1130
+ this.setActiveParts = (parts) => {
1131
+ this.activeParts = Object.assign({}, parts);
1132
+ const hasSlottedButtons = this.el.querySelector('[slot="buttons"]') !== null;
1133
+ if (hasSlottedButtons || this.showDefaultButtons) {
1134
+ return;
1135
+ }
1136
+ this.confirm();
1137
+ };
1138
+ /**
1139
+ * Stencil sometimes sets calendarBodyRef to null on rerender, even though
1140
+ * the element is present. Query for it manually as a fallback.
1141
+ *
1142
+ * TODO(FW-901) Remove when issue is resolved: https://github.com/ionic-team/stencil/issues/3253
1143
+ */
1144
+ this.getCalendarBodyEl = () => {
1145
+ var _a;
1146
+ return this.calendarBodyRef || ((_a = this.el.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('.calendar-body'));
1147
+ };
1148
+ this.initializeKeyboardListeners = () => {
1149
+ const calendarBodyRef = this.getCalendarBodyEl();
1150
+ if (!calendarBodyRef) {
1151
+ return;
1152
+ }
1153
+ const root = this.el.shadowRoot;
1154
+ /**
1155
+ * Get a reference to the month
1156
+ * element we are currently viewing.
1157
+ */
1158
+ const currentMonth = calendarBodyRef.querySelector('.calendar-month:nth-of-type(2)');
1159
+ /**
1160
+ * When focusing the calendar body, we want to pass focus
1161
+ * to the working day, but other days should
1162
+ * only be accessible using the arrow keys. Pressing
1163
+ * Tab should jump between bodies of selectable content.
1164
+ */
1165
+ const checkCalendarBodyFocus = (ev) => {
1166
+ var _a;
1167
+ const record = ev[0];
1168
+ /**
1169
+ * If calendar body was already focused
1170
+ * when this fired or if the calendar body
1171
+ * if not currently focused, we should not re-focus
1172
+ * the inner day.
1173
+ */
1174
+ if (((_a = record.oldValue) === null || _a === void 0 ? void 0 : _a.includes('ion-focused')) ||
1175
+ !calendarBodyRef.classList.contains('ion-focused')) {
1176
+ return;
1177
+ }
1178
+ this.focusWorkingDay(currentMonth);
1179
+ };
1180
+ const mo = new MutationObserver(checkCalendarBodyFocus);
1181
+ mo.observe(calendarBodyRef, { attributeFilter: ['class'], attributeOldValue: true });
1182
+ this.destroyKeyboardMO = () => {
1183
+ mo === null || mo === void 0 ? void 0 : mo.disconnect();
1184
+ };
1185
+ /**
1186
+ * We must use keydown not keyup as we want
1187
+ * to prevent scrolling when using the arrow keys.
1188
+ */
1189
+ calendarBodyRef.addEventListener('keydown', (ev) => {
1190
+ const activeElement = root.activeElement;
1191
+ if (!activeElement || !activeElement.classList.contains('calendar-day')) {
1192
+ return;
1193
+ }
1194
+ const parts = getPartsFromCalendarDay(activeElement);
1195
+ let partsToFocus;
1196
+ switch (ev.key) {
1197
+ case 'ArrowDown':
1198
+ ev.preventDefault();
1199
+ partsToFocus = getNextWeek(parts);
1200
+ break;
1201
+ case 'ArrowUp':
1202
+ ev.preventDefault();
1203
+ partsToFocus = getPreviousWeek(parts);
1204
+ break;
1205
+ case 'ArrowRight':
1206
+ ev.preventDefault();
1207
+ partsToFocus = getNextDay(parts);
1208
+ break;
1209
+ case 'ArrowLeft':
1210
+ ev.preventDefault();
1211
+ partsToFocus = getPreviousDay(parts);
1212
+ break;
1213
+ case 'Home':
1214
+ ev.preventDefault();
1215
+ partsToFocus = getStartOfWeek(parts);
1216
+ break;
1217
+ case 'End':
1218
+ ev.preventDefault();
1219
+ partsToFocus = getEndOfWeek(parts);
1220
+ break;
1221
+ case 'PageUp':
1222
+ ev.preventDefault();
1223
+ partsToFocus = ev.shiftKey ? getPreviousYear(parts) : getPreviousMonth(parts);
1224
+ break;
1225
+ case 'PageDown':
1226
+ ev.preventDefault();
1227
+ partsToFocus = ev.shiftKey ? getNextYear(parts) : getNextMonth(parts);
1228
+ break;
1229
+ /**
1230
+ * Do not preventDefault here
1231
+ * as we do not want to override other
1232
+ * browser defaults such as pressing Enter/Space
1233
+ * to select a day.
1234
+ */
1235
+ default:
1236
+ return;
1237
+ }
1238
+ /**
1239
+ * If the day we want to move focus to is
1240
+ * disabled, do not do anything.
1241
+ */
1242
+ if (isDayDisabled(partsToFocus, this.minParts, this.maxParts)) {
1243
+ return;
1244
+ }
1245
+ this.setWorkingParts(Object.assign(Object.assign({}, this.workingParts), partsToFocus));
1246
+ /**
1247
+ * Give view a chance to re-render
1248
+ * then move focus to the new working day
1249
+ */
1250
+ requestAnimationFrame(() => this.focusWorkingDay(currentMonth));
1251
+ });
1252
+ };
1253
+ this.focusWorkingDay = (currentMonth) => {
1254
+ /**
1255
+ * Get the number of padding days so
1256
+ * we know how much to offset our next selector by
1257
+ * to grab the correct calenday-day element.
1258
+ */
1259
+ const padding = currentMonth.querySelectorAll('.calendar-day-padding');
1260
+ const { day } = this.workingParts;
1261
+ if (day === null) {
1262
+ return;
1263
+ }
1264
+ /**
1265
+ * Get the calendar day element
1266
+ * and focus it.
1267
+ */
1268
+ const dayEl = currentMonth.querySelector(`.calendar-day:nth-of-type(${padding.length + day})`);
1269
+ if (dayEl) {
1270
+ dayEl.focus();
1271
+ }
1272
+ };
1273
+ this.processMinParts = () => {
1274
+ if (this.min === undefined) {
1275
+ this.minParts = undefined;
1276
+ return;
1277
+ }
1278
+ const { month, day, year, hour, minute } = parseDate(this.min);
1279
+ this.minParts = {
1280
+ month,
1281
+ day,
1282
+ year,
1283
+ hour,
1284
+ minute
1285
+ };
1286
+ };
1287
+ this.processMaxParts = () => {
1288
+ if (this.max === undefined) {
1289
+ this.maxParts = undefined;
1290
+ return;
1291
+ }
1292
+ const { month, day, year, hour, minute } = parseDate(this.max);
1293
+ this.maxParts = {
1294
+ month,
1295
+ day,
1296
+ year,
1297
+ hour,
1298
+ minute
1299
+ };
1300
+ };
1301
+ this.initializeCalendarIOListeners = () => {
1302
+ const calendarBodyRef = this.getCalendarBodyEl();
1303
+ if (!calendarBodyRef) {
1304
+ return;
1305
+ }
1306
+ const mode = getIonMode(this);
1307
+ /**
1308
+ * For performance reasons, we only render 3
1309
+ * months at a time: The current month, the previous
1310
+ * month, and the next month. We have IntersectionObservers
1311
+ * on the previous and next month elements to append/prepend
1312
+ * new months.
1313
+ *
1314
+ * We can do this because Stencil is smart enough to not
1315
+ * re-create the .calendar-month containers, but rather
1316
+ * update the content within those containers.
1317
+ *
1318
+ * As an added bonus, WebKit has some troubles with
1319
+ * scroll-snap-stop: always, so not rendering all of
1320
+ * the months in a row allows us to mostly sidestep
1321
+ * that issue.
1322
+ */
1323
+ const months = calendarBodyRef.querySelectorAll('.calendar-month');
1324
+ const startMonth = months[0];
1325
+ const workingMonth = months[1];
1326
+ const endMonth = months[2];
1327
+ /**
1328
+ * Before setting up the IntersectionObserver,
1329
+ * scroll the middle month into view.
1330
+ * scrollIntoView() will scroll entire page
1331
+ * if element is not in viewport. Use scrollLeft instead.
1332
+ */
1333
+ writeTask(() => {
1334
+ calendarBodyRef.scrollLeft = startMonth.clientWidth * (isRTL(this.el) ? -1 : 1);
1335
+ let endIO;
1336
+ let startIO;
1337
+ const ioCallback = (callbackType, entries) => {
1338
+ const refIO = (callbackType === 'start') ? startIO : endIO;
1339
+ const refMonth = (callbackType === 'start') ? startMonth : endMonth;
1340
+ const refMonthFn = (callbackType === 'start') ? getPreviousMonth : getNextMonth;
1341
+ /**
1342
+ * If the month is not fully in view, do not do anything
1343
+ */
1344
+ const ev = entries[0];
1345
+ if (!ev.isIntersecting) {
1346
+ return;
1347
+ }
1348
+ /**
1349
+ * When presenting an inline overlay,
1350
+ * subsequent presentations will cause
1351
+ * the IO to fire again (since the overlay
1352
+ * is now visible and therefore the calendar
1353
+ * months are intersecting).
1354
+ */
1355
+ if (this.overlayIsPresenting) {
1356
+ this.overlayIsPresenting = false;
1357
+ return;
1358
+ }
1359
+ const { month, year, day } = refMonthFn(this.workingParts);
1360
+ if (isMonthDisabled({ month, year, day: null }, {
1361
+ minParts: Object.assign(Object.assign({}, this.minParts), { day: null }),
1362
+ maxParts: Object.assign(Object.assign({}, this.maxParts), { day: null })
1363
+ })) {
1364
+ return;
1365
+ }
1366
+ /**
1367
+ * On iOS, we need to set pointer-events: none
1368
+ * when the user is almost done with the gesture
1369
+ * so that they cannot quickly swipe while
1370
+ * the scrollable container is snapping.
1371
+ * Updating the container while snapping
1372
+ * causes WebKit to snap incorrectly.
1373
+ */
1374
+ if (mode === 'ios') {
1375
+ const ratio = ev.intersectionRatio;
1376
+ // `maxTouchPoints` will be 1 in device preview, but > 1 on device
1377
+ const shouldDisable = Math.abs(ratio - 0.7) <= 0.1 && navigator.maxTouchPoints > 1;
1378
+ if (shouldDisable) {
1379
+ calendarBodyRef.style.setProperty('pointer-events', 'none');
1380
+ return;
1381
+ }
1382
+ }
1383
+ /**
1384
+ * Prevent scrolling for other browsers
1385
+ * to give the DOM time to update and the container
1386
+ * time to properly snap.
1387
+ */
1388
+ calendarBodyRef.style.setProperty('overflow', 'hidden');
1389
+ /**
1390
+ * Remove the IO temporarily
1391
+ * otherwise you can sometimes get duplicate
1392
+ * events when rubber banding.
1393
+ */
1394
+ if (refIO === undefined) {
1395
+ return;
1396
+ }
1397
+ refIO.disconnect();
1398
+ /**
1399
+ * Use a writeTask here to ensure
1400
+ * that the state is updated and the
1401
+ * correct month is scrolled into view
1402
+ * in the same frame. This is not
1403
+ * typically a problem on newer devices
1404
+ * but older/slower device may have a flicker
1405
+ * if we did not do this.
1406
+ */
1407
+ writeTask(() => {
1408
+ // Disconnect all active intersection observers
1409
+ // to avoid a re-render causing a duplicate event.
1410
+ if (this.destroyCalendarIO) {
1411
+ this.destroyCalendarIO();
1412
+ }
1413
+ raf(() => {
1414
+ this.setWorkingParts(Object.assign(Object.assign({}, this.workingParts), { month, day: day, year }));
1415
+ calendarBodyRef.scrollLeft = workingMonth.clientWidth * (isRTL(this.el) ? -1 : 1);
1416
+ calendarBodyRef.style.removeProperty('overflow');
1417
+ calendarBodyRef.style.removeProperty('pointer-events');
1418
+ endIO === null || endIO === void 0 ? void 0 : endIO.observe(endMonth);
1419
+ startIO === null || startIO === void 0 ? void 0 : startIO.observe(startMonth);
1420
+ });
1421
+ /**
1422
+ * Now that state has been updated
1423
+ * and the correct month is in view,
1424
+ * we can resume the IO.
1425
+ */
1426
+ // tslint:disable-next-line
1427
+ if (refIO === undefined) {
1428
+ return;
1429
+ }
1430
+ refIO.observe(refMonth);
1431
+ });
1432
+ };
1433
+ const threshold = mode === 'ios' &&
1434
+ // tslint:disable-next-line
1435
+ typeof navigator !== 'undefined' &&
1436
+ navigator.maxTouchPoints > 1 ?
1437
+ [0.7, 1] : 1;
1438
+ // Intersection observers cannot accurately detect the
1439
+ // intersection with a threshold of 1, when the observed
1440
+ // element width is a sub-pixel value (i.e. 334.05px).
1441
+ // Setting a root margin to 1px solves the issue.
1442
+ const rootMargin = '1px';
1443
+ /**
1444
+ * Listen on the first month to
1445
+ * prepend a new month and on the last
1446
+ * month to append a new month.
1447
+ * The 0.7 threshold is required on ios
1448
+ * so that we can remove pointer-events
1449
+ * when adding new months.
1450
+ * Adding to a scroll snapping container
1451
+ * while the container is snapping does not
1452
+ * completely work as expected in WebKit.
1453
+ * Adding pointer-events: none allows us to
1454
+ * avoid these issues.
1455
+ *
1456
+ * This should be fine on Chromium, but
1457
+ * when you set pointer-events: none
1458
+ * it applies to active gestures which is not
1459
+ * something WebKit does.
1460
+ */
1461
+ endIO = new IntersectionObserver(ev => ioCallback('end', ev), {
1462
+ threshold,
1463
+ root: calendarBodyRef,
1464
+ rootMargin
1465
+ });
1466
+ endIO.observe(endMonth);
1467
+ startIO = new IntersectionObserver(ev => ioCallback('start', ev), {
1468
+ threshold,
1469
+ root: calendarBodyRef,
1470
+ rootMargin
1471
+ });
1472
+ startIO.observe(startMonth);
1473
+ this.destroyCalendarIO = () => {
1474
+ endIO === null || endIO === void 0 ? void 0 : endIO.disconnect();
1475
+ startIO === null || startIO === void 0 ? void 0 : startIO.disconnect();
1476
+ };
1477
+ });
1478
+ };
1479
+ /**
1480
+ * Clean up all listeners except for the overlay
1481
+ * listener. This is so that we can re-create the listeners
1482
+ * if the datetime has been hidden/presented by a modal or popover.
1483
+ */
1484
+ this.destroyInteractionListeners = () => {
1485
+ const { destroyCalendarIO, destroyKeyboardMO } = this;
1486
+ if (destroyCalendarIO !== undefined) {
1487
+ destroyCalendarIO();
1488
+ }
1489
+ if (destroyKeyboardMO !== undefined) {
1490
+ destroyKeyboardMO();
1491
+ }
1492
+ };
1493
+ /**
1494
+ * When doing subsequent presentations of an inline
1495
+ * overlay, the IO callback will fire again causing
1496
+ * the calendar to go back one month. We need to listen
1497
+ * for the presentation of the overlay so we can properly
1498
+ * cancel that IO callback.
1499
+ */
1500
+ this.initializeOverlayListener = () => {
1501
+ const overlay = this.el.closest('ion-popover, ion-modal');
1502
+ if (overlay === null) {
1503
+ return;
1504
+ }
1505
+ const overlayListener = () => {
1506
+ this.overlayIsPresenting = true;
1507
+ };
1508
+ overlay.addEventListener('willPresent', overlayListener);
1509
+ this.destroyOverlayListener = () => {
1510
+ overlay.removeEventListener('willPresent', overlayListener);
1511
+ };
1512
+ };
1513
+ this.processValue = (value) => {
1514
+ const valueToProcess = value || getToday();
1515
+ const { month, day, year, hour, minute, tzOffset } = parseDate(valueToProcess);
1516
+ this.workingParts = {
1517
+ month,
1518
+ day,
1519
+ year,
1520
+ hour,
1521
+ minute,
1522
+ tzOffset,
1523
+ ampm: hour >= 12 ? 'pm' : 'am'
1524
+ };
1525
+ this.activeParts = {
1526
+ month,
1527
+ day,
1528
+ year,
1529
+ hour,
1530
+ minute,
1531
+ tzOffset,
1532
+ ampm: hour >= 12 ? 'pm' : 'am'
1533
+ };
612
1534
  };
613
1535
  this.onFocus = () => {
614
1536
  this.ionFocus.emit();
@@ -616,370 +1538,571 @@ const Datetime = class {
616
1538
  this.onBlur = () => {
617
1539
  this.ionBlur.emit();
618
1540
  };
1541
+ this.hasValue = () => {
1542
+ return this.value != null && this.value !== '';
1543
+ };
1544
+ this.nextMonth = () => {
1545
+ const calendarBodyRef = this.getCalendarBodyEl();
1546
+ if (!calendarBodyRef) {
1547
+ return;
1548
+ }
1549
+ const nextMonth = calendarBodyRef.querySelector('.calendar-month:last-of-type');
1550
+ if (!nextMonth) {
1551
+ return;
1552
+ }
1553
+ const left = nextMonth.offsetWidth * 2;
1554
+ calendarBodyRef.scrollTo({
1555
+ top: 0,
1556
+ left: left * (isRTL(this.el) ? -1 : 1),
1557
+ behavior: 'smooth'
1558
+ });
1559
+ };
1560
+ this.prevMonth = () => {
1561
+ const calendarBodyRef = this.getCalendarBodyEl();
1562
+ if (!calendarBodyRef) {
1563
+ return;
1564
+ }
1565
+ const prevMonth = calendarBodyRef.querySelector('.calendar-month:first-of-type');
1566
+ if (!prevMonth) {
1567
+ return;
1568
+ }
1569
+ calendarBodyRef.scrollTo({
1570
+ top: 0,
1571
+ left: 0,
1572
+ behavior: 'smooth'
1573
+ });
1574
+ };
1575
+ this.toggleMonthAndYearView = () => {
1576
+ this.showMonthAndYear = !this.showMonthAndYear;
1577
+ };
619
1578
  }
620
1579
  disabledChanged() {
621
1580
  this.emitStyle();
622
1581
  }
1582
+ minChanged() {
1583
+ this.processMinParts();
1584
+ }
1585
+ maxChanged() {
1586
+ this.processMaxParts();
1587
+ }
1588
+ yearValuesChanged() {
1589
+ this.parsedYearValues = convertToArrayOfNumbers(this.yearValues);
1590
+ }
1591
+ monthValuesChanged() {
1592
+ this.parsedMonthValues = convertToArrayOfNumbers(this.monthValues);
1593
+ }
1594
+ dayValuesChanged() {
1595
+ this.parsedDayValues = convertToArrayOfNumbers(this.dayValues);
1596
+ }
1597
+ hourValuesChanged() {
1598
+ this.parsedHourValues = convertToArrayOfNumbers(this.hourValues);
1599
+ }
1600
+ minuteValuesChanged() {
1601
+ this.parsedMinuteValues = convertToArrayOfNumbers(this.minuteValues);
1602
+ }
1603
+ activePartsChanged() {
1604
+ this.activePartsClone = this.activeParts;
1605
+ }
623
1606
  /**
624
1607
  * Update the datetime value when the value changes
625
1608
  */
626
1609
  valueChanged() {
627
- this.updateDatetimeValue(this.value);
1610
+ if (this.hasValue()) {
1611
+ /**
1612
+ * Clones the value of the `activeParts` to the private clone, to update
1613
+ * the date display on the current render cycle without causing another render.
1614
+ *
1615
+ * This allows us to update the current value's date/time display without
1616
+ * refocusing or shifting the user's display (leaves the user in place).
1617
+ */
1618
+ const { month, day, year, hour, minute } = parseDate(this.value);
1619
+ this.activePartsClone = Object.assign(Object.assign({}, this.activeParts), { month,
1620
+ day,
1621
+ year,
1622
+ hour,
1623
+ minute });
1624
+ }
628
1625
  this.emitStyle();
629
1626
  this.ionChange.emit({
630
1627
  value: this.value
631
1628
  });
632
1629
  }
633
- componentWillLoad() {
634
- // first see if locale names were provided in the inputs
635
- // then check to see if they're in the config
636
- // if neither were provided then it will use default English names
637
- this.locale = {
638
- // this.locale[type] = convertToArrayOfStrings((this[type] ? this[type] : this.config.get(type), type);
639
- monthNames: convertToArrayOfStrings(this.monthNames, 'monthNames'),
640
- monthShortNames: convertToArrayOfStrings(this.monthShortNames, 'monthShortNames'),
641
- dayNames: convertToArrayOfStrings(this.dayNames, 'dayNames'),
642
- dayShortNames: convertToArrayOfStrings(this.dayShortNames, 'dayShortNames')
1630
+ /**
1631
+ * Confirms the selected datetime value, updates the
1632
+ * `value` property, and optionally closes the popover
1633
+ * or modal that the datetime was presented in.
1634
+ */
1635
+ async confirm(closeOverlay = false) {
1636
+ /**
1637
+ * Prevent convertDataToISO from doing any
1638
+ * kind of transformation based on timezone
1639
+ * This cancels out any change it attempts to make
1640
+ *
1641
+ * Important: Take the timezone offset based on
1642
+ * the date that is currently selected, otherwise
1643
+ * there can be 1 hr difference when dealing w/ DST
1644
+ */
1645
+ const date = new Date(convertDataToISO(this.activeParts));
1646
+ this.activeParts.tzOffset = date.getTimezoneOffset() * -1;
1647
+ this.value = convertDataToISO(this.activeParts);
1648
+ if (closeOverlay) {
1649
+ this.closeParentOverlay();
1650
+ }
1651
+ }
1652
+ /**
1653
+ * Resets the internal state of the datetime but does not update the value.
1654
+ * Passing a valid ISO-8601 string will reset the state of the component to the provided date.
1655
+ * If no value is provided, the internal state will be reset to today.
1656
+ */
1657
+ async reset(startDate) {
1658
+ this.processValue(startDate);
1659
+ }
1660
+ /**
1661
+ * Emits the ionCancel event and
1662
+ * optionally closes the popover
1663
+ * or modal that the datetime was
1664
+ * presented in.
1665
+ */
1666
+ async cancel(closeOverlay = false) {
1667
+ this.ionCancel.emit();
1668
+ if (closeOverlay) {
1669
+ this.closeParentOverlay();
1670
+ }
1671
+ }
1672
+ connectedCallback() {
1673
+ this.clearFocusVisible = startFocusVisible(this.el).destroy;
1674
+ }
1675
+ disconnectedCallback() {
1676
+ if (this.clearFocusVisible) {
1677
+ this.clearFocusVisible();
1678
+ this.clearFocusVisible = undefined;
1679
+ }
1680
+ }
1681
+ initializeListeners() {
1682
+ this.initializeCalendarIOListeners();
1683
+ this.initializeKeyboardListeners();
1684
+ this.initializeOverlayListener();
1685
+ }
1686
+ componentDidLoad() {
1687
+ /**
1688
+ * If a scrollable element is hidden using `display: none`,
1689
+ * it will not have a scroll height meaning we cannot scroll elements
1690
+ * into view. As a result, we will need to wait for the datetime to become
1691
+ * visible if used inside of a modal or a popover otherwise the scrollable
1692
+ * areas will not have the correct values snapped into place.
1693
+ */
1694
+ let visibleIO;
1695
+ const visibleCallback = (entries) => {
1696
+ const ev = entries[0];
1697
+ if (!ev.isIntersecting) {
1698
+ return;
1699
+ }
1700
+ this.initializeListeners();
1701
+ /**
1702
+ * TODO: Datetime needs a frame to ensure that it
1703
+ * can properly scroll contents into view. As a result
1704
+ * we hide the scrollable content until after that frame
1705
+ * so users do not see the content quickly shifting. The downside
1706
+ * is that the content will pop into view a frame after. Maybe there
1707
+ * is a better way to handle this?
1708
+ */
1709
+ writeTask(() => {
1710
+ this.el.classList.add('datetime-ready');
1711
+ });
643
1712
  };
644
- this.updateDatetimeValue(this.value);
645
- this.emitStyle();
1713
+ visibleIO = new IntersectionObserver(visibleCallback, { threshold: 0.01 });
1714
+ /**
1715
+ * Use raf to avoid a race condition between the component loading and
1716
+ * its display animation starting (such as when shown in a modal). This
1717
+ * could cause the datetime to start at a visibility of 0, erroneously
1718
+ * triggering the `hiddenIO` observer below.
1719
+ */
1720
+ raf(() => visibleIO === null || visibleIO === void 0 ? void 0 : visibleIO.observe(this.el));
1721
+ /**
1722
+ * We need to clean up listeners when the datetime is hidden
1723
+ * in a popover/modal so that we can properly scroll containers
1724
+ * back into view if they are re-presented. When the datetime is hidden
1725
+ * the scroll areas have scroll widths/heights of 0px, so any snapping
1726
+ * we did originally has been lost.
1727
+ */
1728
+ let hiddenIO;
1729
+ const hiddenCallback = (entries) => {
1730
+ const ev = entries[0];
1731
+ if (ev.isIntersecting) {
1732
+ return;
1733
+ }
1734
+ this.destroyInteractionListeners();
1735
+ writeTask(() => {
1736
+ this.el.classList.remove('datetime-ready');
1737
+ });
1738
+ };
1739
+ hiddenIO = new IntersectionObserver(hiddenCallback, { threshold: 0 });
1740
+ raf(() => hiddenIO === null || hiddenIO === void 0 ? void 0 : hiddenIO.observe(this.el));
1741
+ /**
1742
+ * Datetime uses Ionic components that emit
1743
+ * ionFocus and ionBlur. These events are
1744
+ * composed meaning they will cross
1745
+ * the shadow dom boundary. We need to
1746
+ * stop propagation on these events otherwise
1747
+ * developers will see 2 ionFocus or 2 ionBlur
1748
+ * events at a time.
1749
+ */
1750
+ const root = getElementRoot(this.el);
1751
+ root.addEventListener('ionFocus', (ev) => ev.stopPropagation());
1752
+ root.addEventListener('ionBlur', (ev) => ev.stopPropagation());
646
1753
  }
647
1754
  /**
648
- * Opens the datetime overlay.
1755
+ * When the presentation is changed, all calendar content is recreated,
1756
+ * so we need to re-init behavior with the new elements.
649
1757
  */
650
- async open() {
651
- if (this.disabled || this.isExpanded) {
1758
+ componentDidRender() {
1759
+ const { presentation, prevPresentation } = this;
1760
+ if (prevPresentation === null) {
1761
+ this.prevPresentation = presentation;
652
1762
  return;
653
1763
  }
654
- const pickerOptions = this.generatePickerOptions();
655
- const picker = await pickerController.create(pickerOptions);
656
- this.isExpanded = true;
657
- picker.onDidDismiss().then(() => {
658
- this.isExpanded = false;
659
- this.setFocus();
660
- });
661
- addEventListener(picker, 'ionPickerColChange', async (event) => {
662
- const data = event.detail;
663
- const colSelectedIndex = data.selectedIndex;
664
- const colOptions = data.options;
665
- const changeData = {};
666
- changeData[data.name] = {
667
- value: colOptions[colSelectedIndex].value
668
- };
669
- if (data.name !== 'ampm' && this.datetimeValue.ampm !== undefined) {
670
- changeData['ampm'] = {
671
- value: this.datetimeValue.ampm
672
- };
673
- }
674
- this.updateDatetimeValue(changeData);
675
- picker.columns = this.generateColumns();
676
- });
677
- await picker.present();
1764
+ if (presentation === prevPresentation) {
1765
+ return;
1766
+ }
1767
+ this.prevPresentation = presentation;
1768
+ this.destroyInteractionListeners();
1769
+ if (this.destroyOverlayListener !== undefined) {
1770
+ this.destroyOverlayListener();
1771
+ }
1772
+ this.initializeListeners();
1773
+ }
1774
+ componentWillLoad() {
1775
+ this.processMinParts();
1776
+ this.processMaxParts();
1777
+ this.processValue(this.value);
1778
+ this.parsedHourValues = convertToArrayOfNumbers(this.hourValues);
1779
+ this.parsedMinuteValues = convertToArrayOfNumbers(this.minuteValues);
1780
+ this.parsedMonthValues = convertToArrayOfNumbers(this.monthValues);
1781
+ this.parsedYearValues = convertToArrayOfNumbers(this.yearValues);
1782
+ this.parsedDayValues = convertToArrayOfNumbers(this.dayValues);
1783
+ this.emitStyle();
678
1784
  }
679
1785
  emitStyle() {
680
1786
  this.ionStyle.emit({
681
1787
  'interactive': true,
682
1788
  'datetime': true,
683
- 'has-placeholder': this.placeholder != null,
684
- 'has-value': this.hasValue(),
685
1789
  'interactive-disabled': this.disabled,
686
1790
  });
687
1791
  }
688
- updateDatetimeValue(value) {
689
- updateDate(this.datetimeValue, value, this.displayTimezone);
690
- }
691
- generatePickerOptions() {
692
- const mode = getIonMode(this);
693
- this.locale = {
694
- monthNames: convertToArrayOfStrings(this.monthNames, 'monthNames'),
695
- monthShortNames: convertToArrayOfStrings(this.monthShortNames, 'monthShortNames'),
696
- dayNames: convertToArrayOfStrings(this.dayNames, 'dayNames'),
697
- dayShortNames: convertToArrayOfStrings(this.dayShortNames, 'dayShortNames')
1792
+ renderFooter() {
1793
+ const { showDefaultButtons, showClearButton } = this;
1794
+ const hasSlottedButtons = this.el.querySelector('[slot="buttons"]') !== null;
1795
+ if (!hasSlottedButtons && !showDefaultButtons && !showClearButton) {
1796
+ return;
1797
+ }
1798
+ const clearButtonClick = () => {
1799
+ this.reset();
1800
+ this.value = undefined;
698
1801
  };
699
- const pickerOptions = Object.assign(Object.assign({ mode }, this.pickerOptions), { columns: this.generateColumns() });
700
- // If the user has not passed in picker buttons,
701
- // add a cancel and ok button to the picker
702
- const buttons = pickerOptions.buttons;
703
- if (!buttons || buttons.length === 0) {
704
- pickerOptions.buttons = [
705
- {
706
- text: this.cancelText,
707
- role: 'cancel',
708
- handler: () => {
709
- this.updateDatetimeValue(this.value);
710
- this.ionCancel.emit();
1802
+ /**
1803
+ * By default we render two buttons:
1804
+ * Cancel - Dismisses the datetime and
1805
+ * does not update the `value` prop.
1806
+ * OK - Dismisses the datetime and
1807
+ * updates the `value` prop.
1808
+ */
1809
+ return (h("div", { class: "datetime-footer" }, h("div", { class: "datetime-buttons" }, h("div", { class: {
1810
+ ['datetime-action-buttons']: true,
1811
+ ['has-clear-button']: this.showClearButton
1812
+ } }, h("slot", { name: "buttons" }, h("ion-buttons", null, showDefaultButtons && h("ion-button", { id: "cancel-button", color: this.color, onClick: () => this.cancel(true) }, this.cancelText), h("div", null, showClearButton && h("ion-button", { id: "clear-button", color: this.color, onClick: () => clearButtonClick() }, this.clearText), showDefaultButtons && h("ion-button", { id: "confirm-button", color: this.color, onClick: () => this.confirm(true) }, this.doneText))))))));
1813
+ }
1814
+ renderYearView() {
1815
+ const { presentation, workingParts, locale } = this;
1816
+ const calendarYears = getCalendarYears(this.todayParts, this.minParts, this.maxParts, this.parsedYearValues);
1817
+ const showMonth = presentation !== 'year';
1818
+ const showYear = presentation !== 'month';
1819
+ const months = getPickerMonths(locale, workingParts, this.minParts, this.maxParts, this.parsedMonthValues);
1820
+ const years = calendarYears.map(year => {
1821
+ return {
1822
+ text: `${year}`,
1823
+ value: year
1824
+ };
1825
+ });
1826
+ const showMonthFirst = isMonthFirstLocale(locale);
1827
+ const columnOrder = showMonthFirst ? 'month-first' : 'year-first';
1828
+ return (h("div", { class: "datetime-year" }, h("div", { class: {
1829
+ 'datetime-year-body': true,
1830
+ [`order-${columnOrder}`]: true
1831
+ } }, h("ion-picker-internal", null, showMonth &&
1832
+ h("ion-picker-column-internal", { class: "month-column", color: this.color, items: months, value: workingParts.month, onIonChange: (ev) => {
1833
+ // Due to a Safari 14 issue we need to destroy
1834
+ // the intersection observer before we update state
1835
+ // and trigger a re-render.
1836
+ if (this.destroyCalendarIO) {
1837
+ this.destroyCalendarIO();
711
1838
  }
712
- },
713
- {
714
- text: this.doneText,
715
- handler: (data) => {
716
- this.updateDatetimeValue(data);
717
- /**
718
- * Prevent convertDataToISO from doing any
719
- * kind of transformation based on timezone
720
- * This cancels out any change it attempts to make
721
- *
722
- * Important: Take the timezone offset based on
723
- * the date that is currently selected, otherwise
724
- * there can be 1 hr difference when dealing w/ DST
725
- */
726
- const date = new Date(convertDataToISO(this.datetimeValue));
727
- // If a custom display timezone is provided, use that tzOffset value instead
728
- this.datetimeValue.tzOffset = (this.displayTimezone !== undefined && this.displayTimezone.length > 0)
729
- ? ((getTimezoneOffset(date, this.displayTimezone)) / 1000 / 60) * -1
730
- : date.getTimezoneOffset() * -1;
731
- this.value = convertDataToISO(this.datetimeValue);
1839
+ this.setWorkingParts(Object.assign(Object.assign({}, this.workingParts), { month: ev.detail.value }));
1840
+ if (presentation === 'month' || presentation === 'month-year') {
1841
+ this.setActiveParts(Object.assign(Object.assign({}, this.activeParts), { month: ev.detail.value }));
732
1842
  }
733
- }
734
- ];
735
- }
736
- return pickerOptions;
737
- }
738
- generateColumns() {
739
- // if a picker format wasn't provided, then fallback
740
- // to use the display format
741
- let template = this.pickerFormat || this.displayFormat || DEFAULT_FORMAT;
742
- if (template.length === 0) {
743
- return [];
744
- }
745
- // make sure we've got up to date sizing information
746
- this.calcMinMax();
747
- // does not support selecting by day name
748
- // automatically remove any day name formats
749
- template = template.replace('DDDD', '{~}').replace('DDD', '{~}');
750
- if (template.indexOf('D') === -1) {
751
- // there is not a day in the template
752
- // replace the day name with a numeric one if it exists
753
- template = template.replace('{~}', 'D');
1843
+ // We can re-attach the intersection observer after
1844
+ // the working parts have been updated.
1845
+ this.initializeCalendarIOListeners();
1846
+ ev.stopPropagation();
1847
+ } }), showYear &&
1848
+ h("ion-picker-column-internal", { class: "year-column", color: this.color, items: years, value: workingParts.year, onIonChange: (ev) => {
1849
+ // Due to a Safari 14 issue we need to destroy
1850
+ // the intersection observer before we update state
1851
+ // and trigger a re-render.
1852
+ if (this.destroyCalendarIO) {
1853
+ this.destroyCalendarIO();
1854
+ }
1855
+ this.setWorkingParts(Object.assign(Object.assign({}, this.workingParts), { year: ev.detail.value }));
1856
+ if (presentation === 'year' || presentation === 'month-year') {
1857
+ this.setActiveParts(Object.assign(Object.assign({}, this.activeParts), { year: ev.detail.value }));
1858
+ }
1859
+ // We can re-attach the intersection observer after
1860
+ // the working parts have been updated.
1861
+ this.initializeCalendarIOListeners();
1862
+ ev.stopPropagation();
1863
+ } })))));
1864
+ }
1865
+ renderCalendarHeader(mode) {
1866
+ const expandedIcon = mode === 'ios' ? chevronDown : caretUpSharp;
1867
+ const collapsedIcon = mode === 'ios' ? chevronForward : caretDownSharp;
1868
+ const prevMonthDisabled = isPrevMonthDisabled(this.workingParts, this.minParts, this.maxParts);
1869
+ const nextMonthDisabled = isNextMonthDisabled(this.workingParts, this.maxParts);
1870
+ return (h("div", { class: "calendar-header" }, h("div", { class: "calendar-action-buttons" }, h("div", { class: "calendar-month-year" }, h("ion-item", { button: true, detail: false, lines: "none", onClick: () => this.toggleMonthAndYearView() }, h("ion-label", null, getMonthAndYear(this.locale, this.workingParts), " ", h("ion-icon", { icon: this.showMonthAndYear ? expandedIcon : collapsedIcon, lazy: false })))), h("div", { class: "calendar-next-prev" }, h("ion-buttons", null, h("ion-button", { disabled: prevMonthDisabled, onClick: () => this.prevMonth() }, h("ion-icon", { slot: "icon-only", icon: chevronBack, lazy: false, flipRtl: true })), h("ion-button", { disabled: nextMonthDisabled, onClick: () => this.nextMonth() }, h("ion-icon", { slot: "icon-only", icon: chevronForward, lazy: false, flipRtl: true }))))), h("div", { class: "calendar-days-of-week" }, getDaysOfWeek(this.locale, mode, this.firstDayOfWeek % 7).map(d => {
1871
+ return h("div", { class: "day-of-week" }, d);
1872
+ }))));
1873
+ }
1874
+ renderMonth(month, year) {
1875
+ const yearAllowed = this.parsedYearValues === undefined || this.parsedYearValues.includes(year);
1876
+ const monthAllowed = this.parsedMonthValues === undefined || this.parsedMonthValues.includes(month);
1877
+ const isCalMonthDisabled = !yearAllowed || !monthAllowed;
1878
+ const swipeDisabled = isMonthDisabled({
1879
+ month,
1880
+ year,
1881
+ day: null
1882
+ }, {
1883
+ // The day is not used when checking if a month is disabled.
1884
+ // Users should be able to access the min or max month, even if the
1885
+ // min/max date is out of bounds (e.g. min is set to Feb 15, Feb should not be disabled).
1886
+ minParts: Object.assign(Object.assign({}, this.minParts), { day: null }),
1887
+ maxParts: Object.assign(Object.assign({}, this.maxParts), { day: null })
1888
+ });
1889
+ // The working month should never have swipe disabled.
1890
+ // Otherwise the CSS scroll snap will not work and the user
1891
+ // can free-scroll the calendar.
1892
+ const isWorkingMonth = this.workingParts.month === month && this.workingParts.year === year;
1893
+ return (h("div", { class: {
1894
+ 'calendar-month': true,
1895
+ // Prevents scroll snap swipe gestures for months outside of the min/max bounds
1896
+ 'calendar-month-disabled': !isWorkingMonth && swipeDisabled
1897
+ } }, h("div", { class: "calendar-month-grid" }, getDaysOfMonth(month, year, this.firstDayOfWeek % 7).map((dateObject, index) => {
1898
+ const { day, dayOfWeek } = dateObject;
1899
+ const referenceParts = { month, day, year };
1900
+ const { isActive, isToday, ariaLabel, ariaSelected, disabled } = getCalendarDayState(this.locale, referenceParts, this.activePartsClone, this.todayParts, this.minParts, this.maxParts, this.parsedDayValues);
1901
+ return (h("button", { tabindex: "-1", "data-day": day, "data-month": month, "data-year": year, "data-index": index, "data-day-of-week": dayOfWeek, disabled: isCalMonthDisabled || disabled, class: {
1902
+ 'calendar-day-padding': day === null,
1903
+ 'calendar-day': true,
1904
+ 'calendar-day-active': isActive,
1905
+ 'calendar-day-today': isToday
1906
+ }, "aria-selected": ariaSelected, "aria-label": ariaLabel, onClick: () => {
1907
+ if (day === null) {
1908
+ return;
1909
+ }
1910
+ this.setWorkingParts(Object.assign(Object.assign({}, this.workingParts), { month,
1911
+ day,
1912
+ year }));
1913
+ this.setActiveParts(Object.assign(Object.assign({}, this.activeParts), { month,
1914
+ day,
1915
+ year }));
1916
+ } }, day));
1917
+ }))));
1918
+ }
1919
+ renderCalendarBody() {
1920
+ return (h("div", { class: "calendar-body ion-focusable", ref: el => this.calendarBodyRef = el, tabindex: "0" }, generateMonths(this.workingParts).map(({ month, year }) => {
1921
+ return this.renderMonth(month, year);
1922
+ })));
1923
+ }
1924
+ renderCalendar(mode) {
1925
+ return (h("div", { class: "datetime-calendar" }, this.renderCalendarHeader(mode), this.renderCalendarBody()));
1926
+ }
1927
+ renderTimeLabel() {
1928
+ const hasSlottedTimeLabel = this.el.querySelector('[slot="time-label"]') !== null;
1929
+ if (!hasSlottedTimeLabel && !this.showDefaultTimeLabel) {
1930
+ return;
754
1931
  }
755
- // make sure no day name replacer is left in the string
756
- template = template.replace(/{~}/g, '');
757
- // parse apart the given template into an array of "formats"
758
- const columns = parseTemplate(template).map((format) => {
759
- // loop through each format in the template
760
- // create a new picker column to build up with data
761
- const key = convertFormatToKey(format);
762
- let values;
763
- // check if they have exact values to use for this date part
764
- // otherwise use the default date part values
765
- const self = this;
766
- values = self[key + 'Values']
767
- ? convertToArrayOfNumbers(self[key + 'Values'], key)
768
- : dateValueRange(format, this.datetimeMin, this.datetimeMax);
769
- const colOptions = values.map(val => {
770
- return {
771
- value: val,
772
- text: renderTextFormat(format, val, undefined, this.locale),
773
- };
774
- });
775
- // cool, we've loaded up the columns with options
776
- // preselect the option for this column
777
- const optValue = getDateValue(this.datetimeValue, format);
778
- const selectedIndex = colOptions.findIndex(opt => opt.value === optValue);
1932
+ return (h("slot", { name: "time-label" }, "Time"));
1933
+ }
1934
+ renderTimePicker(hoursItems, minutesItems, ampmItems, use24Hour) {
1935
+ const { color, activePartsClone, workingParts } = this;
1936
+ return (h("ion-picker-internal", null, h("ion-picker-column-internal", { color: color, value: activePartsClone.hour, items: hoursItems, numericInput: true, onIonChange: (ev) => {
1937
+ this.setWorkingParts(Object.assign(Object.assign({}, workingParts), { hour: ev.detail.value }));
1938
+ this.setActiveParts(Object.assign(Object.assign({}, activePartsClone), { hour: ev.detail.value }));
1939
+ ev.stopPropagation();
1940
+ } }), h("ion-picker-column-internal", { color: color, value: activePartsClone.minute, items: minutesItems, numericInput: true, onIonChange: (ev) => {
1941
+ this.setWorkingParts(Object.assign(Object.assign({}, workingParts), { minute: ev.detail.value }));
1942
+ this.setActiveParts(Object.assign(Object.assign({}, activePartsClone), { minute: ev.detail.value }));
1943
+ ev.stopPropagation();
1944
+ } }), !use24Hour && h("ion-picker-column-internal", { color: color, value: activePartsClone.ampm, items: ampmItems, onIonChange: (ev) => {
1945
+ const hour = calculateHourFromAMPM(workingParts, ev.detail.value);
1946
+ this.setWorkingParts(Object.assign(Object.assign({}, workingParts), { ampm: ev.detail.value, hour }));
1947
+ this.setActiveParts(Object.assign(Object.assign({}, activePartsClone), { ampm: ev.detail.value, hour }));
1948
+ ev.stopPropagation();
1949
+ } })));
1950
+ }
1951
+ renderTimeOverlay(hoursItems, minutesItems, ampmItems, use24Hour) {
1952
+ return [
1953
+ h("div", { class: "time-header" }, this.renderTimeLabel()),
1954
+ h("button", { class: {
1955
+ 'time-body': true,
1956
+ 'time-body-active': this.isTimePopoverOpen
1957
+ }, "aria-expanded": "false", "aria-haspopup": "true", onClick: async (ev) => {
1958
+ const { popoverRef } = this;
1959
+ if (popoverRef) {
1960
+ this.isTimePopoverOpen = true;
1961
+ popoverRef.present(new CustomEvent('ionShadowTarget', {
1962
+ detail: {
1963
+ ionShadowTarget: ev.target
1964
+ }
1965
+ }));
1966
+ await popoverRef.onWillDismiss();
1967
+ this.isTimePopoverOpen = false;
1968
+ }
1969
+ } }, getFormattedTime(this.activePartsClone, use24Hour)),
1970
+ h("ion-popover", { alignment: "center", translucent: true, overlayIndex: 1, arrow: false, onWillPresent: ev => {
1971
+ /**
1972
+ * Intersection Observers do not consistently fire between Blink and Webkit
1973
+ * when toggling the visibility of the popover and trying to scroll the picker
1974
+ * column to the correct time value.
1975
+ *
1976
+ * This will correctly scroll the element position to the correct time value,
1977
+ * before the popover is fully presented.
1978
+ */
1979
+ const cols = ev.target.querySelectorAll('ion-picker-column-internal');
1980
+ // TODO (FW-615): Potentially remove this when intersection observers are fixed in picker column
1981
+ cols.forEach(col => col.scrollActiveItemIntoView());
1982
+ }, style: {
1983
+ '--offset-y': '-10px'
1984
+ },
1985
+ // Allow native browser keyboard events to support up/down/home/end key
1986
+ // navigation within the time picker.
1987
+ keyboardEvents: true, ref: el => this.popoverRef = el }, this.renderTimePicker(hoursItems, minutesItems, ampmItems, use24Hour))
1988
+ ];
1989
+ }
1990
+ /**
1991
+ * Render time picker inside of datetime.
1992
+ * Do not pass color prop to segment on
1993
+ * iOS mode. MD segment has been customized and
1994
+ * should take on the color prop, but iOS
1995
+ * should just be the default segment.
1996
+ */
1997
+ renderTime() {
1998
+ const { workingParts, presentation } = this;
1999
+ const timeOnlyPresentation = presentation === 'time';
2000
+ const use24Hour = is24Hour(this.locale, this.hourCycle);
2001
+ const { hours, minutes, am, pm } = generateTime(this.workingParts, use24Hour ? 'h23' : 'h12', this.minParts, this.maxParts, this.parsedHourValues, this.parsedMinuteValues);
2002
+ const hoursItems = hours.map(hour => {
779
2003
  return {
780
- name: key,
781
- selectedIndex: selectedIndex >= 0 ? selectedIndex : 0,
782
- options: colOptions
2004
+ text: getFormattedHour(hour, use24Hour),
2005
+ value: getInternalHourValue(hour, use24Hour, workingParts.ampm)
783
2006
  };
784
2007
  });
785
- // Normalize min/max
786
- const min = this.datetimeMin;
787
- const max = this.datetimeMax;
788
- ['month', 'day', 'hour', 'minute']
789
- .filter(name => !columns.find(column => column.name === name))
790
- .forEach(name => {
791
- min[name] = 0;
792
- max[name] = 0;
2008
+ const minutesItems = minutes.map(minute => {
2009
+ return {
2010
+ text: addTimePadding(minute),
2011
+ value: minute
2012
+ };
793
2013
  });
794
- return this.validateColumns(divyColumns(columns));
795
- }
796
- validateColumns(columns) {
797
- const today = new Date();
798
- const minCompareVal = dateDataSortValue(this.datetimeMin);
799
- const maxCompareVal = dateDataSortValue(this.datetimeMax);
800
- const yearCol = columns.find(c => c.name === 'year');
801
- let selectedYear = today.getFullYear();
802
- if (yearCol) {
803
- // default to the first value if the current year doesn't exist in the options
804
- if (!yearCol.options.find(col => col.value === today.getFullYear())) {
805
- selectedYear = yearCol.options[0].value;
806
- }
807
- const selectedIndex = yearCol.selectedIndex;
808
- if (selectedIndex !== undefined) {
809
- const yearOpt = yearCol.options[selectedIndex];
810
- if (yearOpt) {
811
- // they have a selected year value
812
- selectedYear = yearOpt.value;
813
- }
814
- }
815
- }
816
- const selectedMonth = this.validateColumn(columns, 'month', 1, minCompareVal, maxCompareVal, [selectedYear, 0, 0, 0, 0], [selectedYear, 12, 31, 23, 59]);
817
- const numDaysInMonth = daysInMonth(selectedMonth, selectedYear);
818
- const selectedDay = this.validateColumn(columns, 'day', 2, minCompareVal, maxCompareVal, [selectedYear, selectedMonth, 0, 0, 0], [selectedYear, selectedMonth, numDaysInMonth, 23, 59]);
819
- const selectedHour = this.validateColumn(columns, 'hour', 3, minCompareVal, maxCompareVal, [selectedYear, selectedMonth, selectedDay, 0, 0], [selectedYear, selectedMonth, selectedDay, 23, 59]);
820
- this.validateColumn(columns, 'minute', 4, minCompareVal, maxCompareVal, [selectedYear, selectedMonth, selectedDay, selectedHour, 0], [selectedYear, selectedMonth, selectedDay, selectedHour, 59]);
821
- return columns;
822
- }
823
- calcMinMax() {
824
- const todaysYear = new Date().getFullYear();
825
- if (this.yearValues !== undefined) {
826
- const years = convertToArrayOfNumbers(this.yearValues, 'year');
827
- if (this.min === undefined) {
828
- this.min = Math.min(...years).toString();
829
- }
830
- if (this.max === undefined) {
831
- this.max = Math.max(...years).toString();
832
- }
833
- }
834
- else {
835
- if (this.min === undefined) {
836
- this.min = (todaysYear - 100).toString();
837
- }
838
- if (this.max === undefined) {
839
- this.max = todaysYear.toString();
840
- }
841
- }
842
- const min = this.datetimeMin = parseDate(this.min);
843
- const max = this.datetimeMax = parseDate(this.max);
844
- min.year = min.year || todaysYear;
845
- max.year = max.year || todaysYear;
846
- min.month = min.month || 1;
847
- max.month = max.month || 12;
848
- min.day = min.day || 1;
849
- max.day = max.day || 31;
850
- min.hour = min.hour || 0;
851
- max.hour = max.hour === undefined ? 23 : max.hour;
852
- min.minute = min.minute || 0;
853
- max.minute = max.minute === undefined ? 59 : max.minute;
854
- min.second = min.second || 0;
855
- max.second = max.second === undefined ? 59 : max.second;
856
- // Ensure min/max constraints
857
- if (min.year > max.year) {
858
- console.error('min.year > max.year');
859
- min.year = max.year - 100;
2014
+ const ampmItems = [];
2015
+ if (am) {
2016
+ ampmItems.push({
2017
+ text: 'AM',
2018
+ value: 'am'
2019
+ });
860
2020
  }
861
- if (min.year === max.year) {
862
- if (min.month > max.month) {
863
- console.error('min.month > max.month');
864
- min.month = 1;
865
- }
866
- else if (min.month === max.month && min.day > max.day) {
867
- console.error('min.day > max.day');
868
- min.day = 1;
869
- }
2021
+ if (pm) {
2022
+ ampmItems.push({
2023
+ text: 'PM',
2024
+ value: 'pm'
2025
+ });
870
2026
  }
2027
+ return (h("div", { class: "datetime-time" }, timeOnlyPresentation ? this.renderTimePicker(hoursItems, minutesItems, ampmItems, use24Hour) : this.renderTimeOverlay(hoursItems, minutesItems, ampmItems, use24Hour)));
871
2028
  }
872
- validateColumn(columns, name, index, min, max, lowerBounds, upperBounds) {
873
- const column = columns.find(c => c.name === name);
874
- if (!column) {
875
- return 0;
876
- }
877
- const lb = lowerBounds.slice();
878
- const ub = upperBounds.slice();
879
- const options = column.options;
880
- let indexMin = options.length - 1;
881
- let indexMax = 0;
882
- for (let i = 0; i < options.length; i++) {
883
- const opts = options[i];
884
- const value = opts.value;
885
- lb[index] = opts.value;
886
- ub[index] = opts.value;
887
- const disabled = opts.disabled = (value < lowerBounds[index] ||
888
- value > upperBounds[index] ||
889
- dateSortValue(ub[0], ub[1], ub[2], ub[3], ub[4]) < min ||
890
- dateSortValue(lb[0], lb[1], lb[2], lb[3], lb[4]) > max);
891
- if (!disabled) {
892
- indexMin = Math.min(indexMin, i);
893
- indexMax = Math.max(indexMax, i);
894
- }
895
- }
896
- const selectedIndex = column.selectedIndex = clamp(indexMin, column.selectedIndex, indexMax);
897
- const opt = column.options[selectedIndex];
898
- if (opt) {
899
- return opt.value;
900
- }
901
- return 0;
902
- }
903
- get text() {
904
- // create the text of the formatted data
905
- const template = this.displayFormat || this.pickerFormat || DEFAULT_FORMAT;
906
- if (this.value === undefined ||
907
- this.value === null ||
908
- this.value.length === 0) {
2029
+ renderCalendarViewHeader(mode) {
2030
+ const hasSlottedTitle = this.el.querySelector('[slot="title"]') !== null;
2031
+ if (!hasSlottedTitle && !this.showDefaultTitle) {
909
2032
  return;
910
2033
  }
911
- return renderDatetime(template, this.datetimeValue, this.locale);
2034
+ return (h("div", { class: "datetime-header" }, h("div", { class: "datetime-title" }, h("slot", { name: "title" }, "Select Date")), mode === 'md' && h("div", { class: "datetime-selected-date" }, getMonthAndDay(this.locale, this.activeParts))));
912
2035
  }
913
- hasValue() {
914
- return this.text !== undefined;
915
- }
916
- setFocus() {
917
- if (this.buttonEl) {
918
- this.buttonEl.focus();
2036
+ renderDatetime(mode) {
2037
+ const { presentation } = this;
2038
+ switch (presentation) {
2039
+ case 'date-time':
2040
+ return [
2041
+ this.renderCalendarViewHeader(mode),
2042
+ this.renderCalendar(mode),
2043
+ this.renderYearView(),
2044
+ this.renderTime(),
2045
+ this.renderFooter()
2046
+ ];
2047
+ case 'time-date':
2048
+ return [
2049
+ this.renderCalendarViewHeader(mode),
2050
+ this.renderTime(),
2051
+ this.renderCalendar(mode),
2052
+ this.renderYearView(),
2053
+ this.renderFooter()
2054
+ ];
2055
+ case 'time':
2056
+ return [
2057
+ this.renderTime(),
2058
+ this.renderFooter()
2059
+ ];
2060
+ case 'month':
2061
+ case 'month-year':
2062
+ case 'year':
2063
+ return [
2064
+ this.renderYearView(),
2065
+ this.renderFooter()
2066
+ ];
2067
+ default:
2068
+ return [
2069
+ this.renderCalendarViewHeader(mode),
2070
+ this.renderCalendar(mode),
2071
+ this.renderYearView(),
2072
+ this.renderFooter()
2073
+ ];
919
2074
  }
920
2075
  }
921
2076
  render() {
922
- const { inputId, text, disabled, readonly, isExpanded, el, placeholder } = this;
2077
+ const { name, value, disabled, el, color, isPresented, readonly, showMonthAndYear, presentation, size } = this;
923
2078
  const mode = getIonMode(this);
924
- const labelId = inputId + '-lbl';
925
- const label = findItemLabel(el);
926
- const addPlaceholderClass = (text === undefined && placeholder != null) ? true : false;
927
- // If selected text has been passed in, use that first
928
- // otherwise use the placeholder
929
- const datetimeText = text === undefined
930
- ? (placeholder != null ? placeholder : '')
931
- : text;
932
- const datetimeTextPart = text === undefined
933
- ? (placeholder != null ? 'placeholder' : undefined)
934
- : 'text';
935
- if (label) {
936
- label.id = labelId;
937
- }
938
- renderHiddenInput(true, el, this.name, this.value, this.disabled);
939
- return (h(Host, { onClick: this.onClick, "aria-disabled": disabled ? 'true' : null, "aria-expanded": `${isExpanded}`, "aria-haspopup": "true", "aria-labelledby": labelId, class: {
2079
+ const isMonthAndYearPresentation = presentation === 'year' || presentation === 'month' || presentation === 'month-year';
2080
+ const shouldShowMonthAndYear = showMonthAndYear || isMonthAndYearPresentation;
2081
+ renderHiddenInput(true, el, name, value, disabled);
2082
+ return (h(Host, { "aria-disabled": disabled ? 'true' : null, onFocus: this.onFocus, onBlur: this.onBlur, class: Object.assign({}, createColorClasses(color, {
940
2083
  [mode]: true,
941
- 'datetime-disabled': disabled,
942
- 'datetime-readonly': readonly,
943
- 'datetime-placeholder': addPlaceholderClass,
944
- 'in-item': hostContext('ion-item', el)
945
- } }, h("div", { class: "datetime-text", part: datetimeTextPart }, datetimeText), h("button", { type: "button", onFocus: this.onFocus, onBlur: this.onBlur, disabled: this.disabled, ref: btnEl => this.buttonEl = btnEl })));
2084
+ ['datetime-presented']: isPresented,
2085
+ ['datetime-readonly']: readonly,
2086
+ ['datetime-disabled']: disabled,
2087
+ 'show-month-and-year': shouldShowMonthAndYear,
2088
+ [`datetime-presentation-${presentation}`]: true,
2089
+ [`datetime-size-${size}`]: true
2090
+ })) }, this.renderDatetime(mode)));
946
2091
  }
947
2092
  get el() { return getElement(this); }
948
2093
  static get watchers() { return {
949
2094
  "disabled": ["disabledChanged"],
2095
+ "min": ["minChanged"],
2096
+ "max": ["maxChanged"],
2097
+ "yearValues": ["yearValuesChanged"],
2098
+ "monthValues": ["monthValuesChanged"],
2099
+ "dayValues": ["dayValuesChanged"],
2100
+ "hourValues": ["hourValuesChanged"],
2101
+ "minuteValues": ["minuteValuesChanged"],
2102
+ "activeParts": ["activePartsChanged"],
950
2103
  "value": ["valueChanged"]
951
2104
  }; }
952
2105
  };
953
- const divyColumns = (columns) => {
954
- const columnsWidth = [];
955
- let col;
956
- let width;
957
- for (let i = 0; i < columns.length; i++) {
958
- col = columns[i];
959
- columnsWidth.push(0);
960
- for (const option of col.options) {
961
- width = option.text.length;
962
- if (width > columnsWidth[i]) {
963
- columnsWidth[i] = width;
964
- }
965
- }
966
- }
967
- if (columnsWidth.length === 2) {
968
- width = Math.max(columnsWidth[0], columnsWidth[1]);
969
- columns[0].align = 'right';
970
- columns[1].align = 'left';
971
- columns[0].optionsWidth = columns[1].optionsWidth = `${width * 17}px`;
972
- }
973
- else if (columnsWidth.length === 3) {
974
- width = Math.max(columnsWidth[0], columnsWidth[2]);
975
- columns[0].align = 'right';
976
- columns[1].columnWidth = `${columnsWidth[1] * 17}px`;
977
- columns[0].optionsWidth = columns[2].optionsWidth = `${width * 17}px`;
978
- columns[2].align = 'left';
979
- }
980
- return columns;
981
- };
982
- const DEFAULT_FORMAT = 'MMM D, YYYY';
983
2106
  let datetimeIds = 0;
984
2107
  Datetime.style = {
985
2108
  ios: datetimeIosCss,