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