@nova-design-system/nova-webcomponents 3.0.0 → 3.1.0

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 (436) hide show
  1. package/dist/cjs/{constants-bcd6b2e2.js → constants-8fb8ccc0.js} +14 -1
  2. package/dist/cjs/constants-8fb8ccc0.js.map +1 -0
  3. package/dist/cjs/index-9bda5507.js +4 -4
  4. package/dist/cjs/index.cjs.js +4 -471
  5. package/dist/cjs/index.cjs.js.map +1 -1
  6. package/dist/cjs/loader.cjs.js +1 -1
  7. package/dist/cjs/native.cjs.js +1 -1
  8. package/dist/cjs/nv-alert.cjs.entry.js +5 -5
  9. package/dist/cjs/nv-alert.cjs.entry.js.map +1 -1
  10. package/dist/cjs/nv-avatar.cjs.entry.js +1 -1
  11. package/dist/cjs/nv-badge_2.cjs.entry.js +17 -8
  12. package/dist/cjs/nv-badge_2.cjs.entry.js.map +1 -1
  13. package/dist/cjs/nv-button.cjs.entry.js +1 -1
  14. package/dist/cjs/nv-calendar.cjs.entry.js +841 -842
  15. package/dist/cjs/nv-calendar.cjs.entry.js.map +1 -1
  16. package/dist/cjs/nv-datagrid.cjs.entry.js +376 -39
  17. package/dist/cjs/nv-datagrid.cjs.entry.js.map +1 -1
  18. package/dist/cjs/nv-dialog.cjs.entry.js +18 -12
  19. package/dist/cjs/nv-dialog.cjs.entry.js.map +1 -1
  20. package/dist/cjs/nv-dialogfooter_2.cjs.entry.js +1 -1
  21. package/dist/cjs/nv-fielddate.cjs.entry.js +8 -17
  22. package/dist/cjs/nv-fielddate.cjs.entry.js.map +1 -1
  23. package/dist/cjs/nv-fielddaterange.cjs.entry.js +26 -28
  24. package/dist/cjs/nv-fielddaterange.cjs.entry.js.map +1 -1
  25. package/dist/cjs/nv-fielddropdown.cjs.entry.js +12 -5
  26. package/dist/cjs/nv-fielddropdown.cjs.entry.js.map +1 -1
  27. package/dist/cjs/nv-fielddropdownitem.cjs.entry.js +1 -1
  28. package/dist/cjs/nv-fieldmultiselect.cjs.entry.js +10 -4
  29. package/dist/cjs/nv-fieldmultiselect.cjs.entry.js.map +1 -1
  30. package/dist/cjs/nv-fieldnumber.cjs.entry.js +8 -4
  31. package/dist/cjs/nv-fieldnumber.cjs.entry.js.map +1 -1
  32. package/dist/cjs/nv-fieldpassword.cjs.entry.js +8 -4
  33. package/dist/cjs/nv-fieldpassword.cjs.entry.js.map +1 -1
  34. package/dist/cjs/nv-fieldradio.cjs.entry.js +3 -3
  35. package/dist/cjs/nv-fieldselect.cjs.entry.js +10 -6
  36. package/dist/cjs/nv-fieldselect.cjs.entry.js.map +1 -1
  37. package/dist/cjs/nv-fieldtext.cjs.entry.js +8 -4
  38. package/dist/cjs/nv-fieldtext.cjs.entry.js.map +1 -1
  39. package/dist/cjs/nv-fieldtextarea.cjs.entry.js +8 -4
  40. package/dist/cjs/nv-fieldtextarea.cjs.entry.js.map +1 -1
  41. package/dist/cjs/nv-fieldtime.cjs.entry.js +15 -12
  42. package/dist/cjs/nv-fieldtime.cjs.entry.js.map +1 -1
  43. package/dist/cjs/nv-icon.cjs.entry.js +3 -3
  44. package/dist/cjs/nv-icon.cjs.entry.js.map +1 -1
  45. package/dist/cjs/nv-iconbutton_2.cjs.entry.js +2 -2
  46. package/dist/cjs/nv-menu.cjs.entry.js +3 -1
  47. package/dist/cjs/nv-menu.cjs.entry.js.map +1 -1
  48. package/dist/cjs/nv-menuitem.cjs.entry.js +1 -1
  49. package/dist/cjs/nv-popover.cjs.entry.js +1 -1
  50. package/dist/cjs/nv-row.cjs.entry.js +1 -1
  51. package/dist/cjs/nv-stack.cjs.entry.js +1 -1
  52. package/dist/cjs/nv-table.cjs.entry.js +2 -2
  53. package/dist/cjs/nv-table.cjs.entry.js.map +1 -1
  54. package/dist/cjs/nv-toggle.cjs.entry.js +2 -2
  55. package/dist/cjs/nv-tooltip.cjs.entry.js +1 -1
  56. package/dist/collection/components/nv-alert/nv-alert.css +3 -0
  57. package/dist/collection/components/nv-alert/nv-alert.js +6 -11
  58. package/dist/collection/components/nv-alert/nv-alert.js.map +1 -1
  59. package/dist/collection/components/nv-badge/nv-badge.css +181 -1
  60. package/dist/collection/components/nv-badge/nv-badge.docs.js +20 -1
  61. package/dist/collection/components/nv-badge/nv-badge.docs.js.map +1 -1
  62. package/dist/collection/components/nv-badge/nv-badge.js +39 -15
  63. package/dist/collection/components/nv-badge/nv-badge.js.map +1 -1
  64. package/dist/collection/components/nv-breadcrumbs/nv-breadcrumbs.docs.js +0 -1
  65. package/dist/collection/components/nv-breadcrumbs/nv-breadcrumbs.docs.js.map +1 -1
  66. package/dist/collection/components/nv-calendar/nv-calendar.css +19 -0
  67. package/dist/collection/components/nv-calendar/nv-calendar.docs.js +33 -38
  68. package/dist/collection/components/nv-calendar/nv-calendar.docs.js.map +1 -1
  69. package/dist/collection/components/nv-calendar/nv-calendar.js +680 -897
  70. package/dist/collection/components/nv-calendar/nv-calendar.js.map +1 -1
  71. package/dist/collection/components/nv-calendar/nv-calendar.utils.js +202 -0
  72. package/dist/collection/components/nv-calendar/nv-calendar.utils.js.map +1 -0
  73. package/dist/collection/components/nv-calendar/test/nv-calendar.utils.test.js +667 -0
  74. package/dist/collection/components/nv-calendar/test/nv-calendar.utils.test.js.map +1 -0
  75. package/dist/collection/components/nv-datagrid/nv-datagrid.css +98 -0
  76. package/dist/collection/components/nv-datagrid/nv-datagrid.docs.js +103 -5
  77. package/dist/collection/components/nv-datagrid/nv-datagrid.docs.js.map +1 -1
  78. package/dist/collection/components/nv-datagrid/nv-datagrid.js +391 -56
  79. package/dist/collection/components/nv-datagrid/nv-datagrid.js.map +1 -1
  80. package/dist/collection/components/nv-dialog/nv-dialog.css +29 -5
  81. package/dist/collection/components/nv-dialog/nv-dialog.docs.js +0 -1
  82. package/dist/collection/components/nv-dialog/nv-dialog.docs.js.map +1 -1
  83. package/dist/collection/components/nv-dialog/nv-dialog.js +16 -10
  84. package/dist/collection/components/nv-dialog/nv-dialog.js.map +1 -1
  85. package/dist/collection/components/nv-fielddate/nv-fielddate.docs.js +16 -8
  86. package/dist/collection/components/nv-fielddate/nv-fielddate.docs.js.map +1 -1
  87. package/dist/collection/components/nv-fielddate/nv-fielddate.js +48 -39
  88. package/dist/collection/components/nv-fielddate/nv-fielddate.js.map +1 -1
  89. package/dist/collection/components/nv-fielddate/styles/nv-fielddate.css +7 -0
  90. package/dist/collection/components/nv-fielddaterange/nv-fielddaterange.docs.js +12 -15
  91. package/dist/collection/components/nv-fielddaterange/nv-fielddaterange.docs.js.map +1 -1
  92. package/dist/collection/components/nv-fielddaterange/nv-fielddaterange.js +75 -64
  93. package/dist/collection/components/nv-fielddaterange/nv-fielddaterange.js.map +1 -1
  94. package/dist/collection/components/nv-fielddaterange/styles/nv-fielddaterange.css +13 -11
  95. package/dist/collection/components/nv-fielddropdown/nv-fielddropdown.docs.js +8 -0
  96. package/dist/collection/components/nv-fielddropdown/nv-fielddropdown.docs.js.map +1 -1
  97. package/dist/collection/components/nv-fielddropdown/nv-fielddropdown.js +31 -4
  98. package/dist/collection/components/nv-fielddropdown/nv-fielddropdown.js.map +1 -1
  99. package/dist/collection/components/nv-fielddropdown/styles/nv-fielddropdown.css +5 -0
  100. package/dist/collection/components/nv-fielddropdownitem/nv-fielddropdownitem.js +1 -1
  101. package/dist/collection/components/nv-fielddropdownitemcheck/nv-fielddropdownitemcheck.js +1 -1
  102. package/dist/collection/components/nv-fieldmultiselect/nv-fieldmultiselect.css +24 -0
  103. package/dist/collection/components/nv-fieldmultiselect/nv-fieldmultiselect.docs.js +8 -1
  104. package/dist/collection/components/nv-fieldmultiselect/nv-fieldmultiselect.docs.js.map +1 -1
  105. package/dist/collection/components/nv-fieldmultiselect/nv-fieldmultiselect.js +29 -3
  106. package/dist/collection/components/nv-fieldmultiselect/nv-fieldmultiselect.js.map +1 -1
  107. package/dist/collection/components/nv-fieldnumber/nv-fieldnumber.css +5 -0
  108. package/dist/collection/components/nv-fieldnumber/nv-fieldnumber.docs.js +8 -0
  109. package/dist/collection/components/nv-fieldnumber/nv-fieldnumber.docs.js.map +1 -1
  110. package/dist/collection/components/nv-fieldnumber/nv-fieldnumber.js +27 -3
  111. package/dist/collection/components/nv-fieldnumber/nv-fieldnumber.js.map +1 -1
  112. package/dist/collection/components/nv-fieldpassword/nv-fieldpassword.css +5 -0
  113. package/dist/collection/components/nv-fieldpassword/nv-fieldpassword.docs.js +8 -0
  114. package/dist/collection/components/nv-fieldpassword/nv-fieldpassword.docs.js.map +1 -1
  115. package/dist/collection/components/nv-fieldpassword/nv-fieldpassword.js +27 -3
  116. package/dist/collection/components/nv-fieldpassword/nv-fieldpassword.js.map +1 -1
  117. package/dist/collection/components/nv-fieldradio/nv-fieldradio.js +3 -3
  118. package/dist/collection/components/nv-fieldselect/nv-fieldselect.css +5 -0
  119. package/dist/collection/components/nv-fieldselect/nv-fieldselect.docs.js +8 -0
  120. package/dist/collection/components/nv-fieldselect/nv-fieldselect.docs.js.map +1 -1
  121. package/dist/collection/components/nv-fieldselect/nv-fieldselect.js +29 -5
  122. package/dist/collection/components/nv-fieldselect/nv-fieldselect.js.map +1 -1
  123. package/dist/collection/components/nv-fieldtext/nv-fieldtext.css +5 -0
  124. package/dist/collection/components/nv-fieldtext/nv-fieldtext.docs.js +8 -0
  125. package/dist/collection/components/nv-fieldtext/nv-fieldtext.docs.js.map +1 -1
  126. package/dist/collection/components/nv-fieldtext/nv-fieldtext.js +27 -3
  127. package/dist/collection/components/nv-fieldtext/nv-fieldtext.js.map +1 -1
  128. package/dist/collection/components/nv-fieldtextarea/nv-fieldtextarea.css +23 -0
  129. package/dist/collection/components/nv-fieldtextarea/nv-fieldtextarea.docs.js +8 -0
  130. package/dist/collection/components/nv-fieldtextarea/nv-fieldtextarea.docs.js.map +1 -1
  131. package/dist/collection/components/nv-fieldtextarea/nv-fieldtextarea.js +27 -3
  132. package/dist/collection/components/nv-fieldtextarea/nv-fieldtextarea.js.map +1 -1
  133. package/dist/collection/components/nv-fieldtime/nv-fieldtime.js +13 -10
  134. package/dist/collection/components/nv-fieldtime/nv-fieldtime.js.map +1 -1
  135. package/dist/collection/components/nv-fieldtime/styles/nv-fieldtime.css +19 -2
  136. package/dist/collection/components/nv-icon/nv-icon.js +1 -1
  137. package/dist/collection/components/nv-icon/nv-icons.js +3 -470
  138. package/dist/collection/components/nv-icon/nv-icons.js.map +1 -1
  139. package/dist/collection/components/nv-iconbutton/nv-iconbutton.js +1 -1
  140. package/dist/collection/components/nv-loader/nv-loader.js +1 -1
  141. package/dist/collection/components/nv-menu/nv-menu.js +3 -1
  142. package/dist/collection/components/nv-menu/nv-menu.js.map +1 -1
  143. package/dist/collection/components/nv-menuitem/nv-menuitem.js +2 -2
  144. package/dist/collection/components/nv-popover/nv-popover.js +1 -1
  145. package/dist/collection/components/nv-row/nv-row.js +1 -1
  146. package/dist/collection/components/nv-stack/nv-stack.js +1 -1
  147. package/dist/collection/components/nv-table/nv-table.js +8 -11
  148. package/dist/collection/components/nv-table/nv-table.js.map +1 -1
  149. package/dist/collection/components/nv-toggle/nv-toggle.js +2 -2
  150. package/dist/collection/components/nv-tooltip/nv-tooltip.js +1 -1
  151. package/dist/collection/index.js.map +1 -1
  152. package/dist/collection/templates/navigation.docs.js +0 -1
  153. package/dist/collection/templates/navigation.docs.js.map +1 -1
  154. package/dist/collection/utils/constants.js +11 -0
  155. package/dist/collection/utils/constants.js.map +1 -1
  156. package/dist/components/index.js +4 -471
  157. package/dist/components/index.js.map +1 -1
  158. package/dist/components/nv-alert.js +6 -6
  159. package/dist/components/nv-alert.js.map +1 -1
  160. package/dist/components/nv-avatar.js +2 -2
  161. package/dist/components/nv-badge.js +1 -1
  162. package/dist/components/nv-breadcrumb.js +2 -2
  163. package/dist/components/nv-button.js +1 -1
  164. package/dist/components/nv-calendar.js +1 -1
  165. package/dist/components/nv-datagrid.js +400 -43
  166. package/dist/components/nv-datagrid.js.map +1 -1
  167. package/dist/components/nv-dialog.js +22 -16
  168. package/dist/components/nv-dialog.js.map +1 -1
  169. package/dist/components/nv-dialogfooter.js +1 -1
  170. package/dist/components/nv-fielddate.js +18 -26
  171. package/dist/components/nv-fielddate.js.map +1 -1
  172. package/dist/components/nv-fielddaterange.js +37 -38
  173. package/dist/components/nv-fielddaterange.js.map +1 -1
  174. package/dist/components/nv-fielddropdown.js +18 -10
  175. package/dist/components/nv-fielddropdown.js.map +1 -1
  176. package/dist/components/nv-fielddropdownitem.js +1 -1
  177. package/dist/components/nv-fielddropdownitemcheck.js +1 -1
  178. package/dist/components/nv-fieldmultiselect.js +17 -10
  179. package/dist/components/nv-fieldmultiselect.js.map +1 -1
  180. package/dist/components/nv-fieldnumber.js +13 -8
  181. package/dist/components/nv-fieldnumber.js.map +1 -1
  182. package/dist/components/nv-fieldpassword.js +12 -7
  183. package/dist/components/nv-fieldpassword.js.map +1 -1
  184. package/dist/components/nv-fieldradio.js +3 -3
  185. package/dist/components/nv-fieldselect.js +14 -9
  186. package/dist/components/nv-fieldselect.js.map +1 -1
  187. package/dist/components/nv-fieldtext.js +1 -158
  188. package/dist/components/nv-fieldtext.js.map +1 -1
  189. package/dist/components/nv-fieldtextarea.js +10 -5
  190. package/dist/components/nv-fieldtextarea.js.map +1 -1
  191. package/dist/components/nv-fieldtime.js +19 -16
  192. package/dist/components/nv-fieldtime.js.map +1 -1
  193. package/dist/components/nv-icon.js +1 -1
  194. package/dist/components/nv-iconbutton.js +1 -1
  195. package/dist/components/nv-loader.js +1 -1
  196. package/dist/components/nv-menu.js +6 -4
  197. package/dist/components/nv-menu.js.map +1 -1
  198. package/dist/components/nv-menuitem.js +1 -1
  199. package/dist/components/nv-popover.js +1 -1
  200. package/dist/components/nv-row.js +1 -1
  201. package/dist/components/nv-stack.js +1 -1
  202. package/dist/components/nv-table.js +2 -2
  203. package/dist/components/nv-table.js.map +1 -1
  204. package/dist/components/nv-toggle.js +2 -2
  205. package/dist/components/nv-tooltip.js +1 -1
  206. package/dist/components/p-0a0f6daf.js +187 -0
  207. package/dist/components/p-0a0f6daf.js.map +1 -0
  208. package/dist/components/{p-b7b78e64.js → p-10b37876.js} +2 -2
  209. package/dist/components/{p-b7b78e64.js.map → p-10b37876.js.map} +1 -1
  210. package/dist/components/{p-dc3faba3.js → p-10faa938.js} +4 -4
  211. package/dist/components/{p-dc3faba3.js.map → p-10faa938.js.map} +1 -1
  212. package/dist/{esm/constants-98e2dcc2.js → components/p-1f505531.js} +15 -2
  213. package/dist/components/p-1f505531.js.map +1 -0
  214. package/dist/components/{p-2012b8ba.js → p-35a70c5e.js} +2 -2
  215. package/dist/components/{p-2012b8ba.js.map → p-35a70c5e.js.map} +1 -1
  216. package/dist/components/{p-6c364a23.js → p-41c56ddc.js} +5 -5
  217. package/dist/components/{p-6c364a23.js.map → p-41c56ddc.js.map} +1 -1
  218. package/dist/components/{p-a30b55fc.js → p-608eb9da.js} +2 -2
  219. package/dist/components/{p-a30b55fc.js.map → p-608eb9da.js.map} +1 -1
  220. package/dist/components/p-76646ce9.js +88 -0
  221. package/dist/components/p-76646ce9.js.map +1 -0
  222. package/dist/components/p-854c32dc.js +1132 -0
  223. package/dist/components/p-854c32dc.js.map +1 -0
  224. package/dist/components/p-9decffb6.js +167 -0
  225. package/dist/components/p-9decffb6.js.map +1 -0
  226. package/dist/components/{p-2d9ba7d3.js → p-a2527411.js} +3 -3
  227. package/dist/components/{p-2d9ba7d3.js.map → p-a2527411.js.map} +1 -1
  228. package/dist/components/{p-f4d86795.js → p-b48d5a94.js} +3 -3
  229. package/dist/components/{p-f4d86795.js.map → p-b48d5a94.js.map} +1 -1
  230. package/dist/components/{p-4d3ec142.js → p-eb632278.js} +3 -3
  231. package/dist/components/{p-4d3ec142.js.map → p-eb632278.js.map} +1 -1
  232. package/dist/components/{p-150daf68.js → p-f5cb0a63.js} +2 -2
  233. package/dist/components/{p-150daf68.js.map → p-f5cb0a63.js.map} +1 -1
  234. package/dist/components/{p-c14f6b8e.js → p-f76bb0c3.js} +3 -3
  235. package/dist/components/{p-c14f6b8e.js.map → p-f76bb0c3.js.map} +1 -1
  236. package/dist/{components/p-8348db09.js → esm/constants-b97e736d.js} +15 -2
  237. package/dist/esm/constants-b97e736d.js.map +1 -0
  238. package/dist/esm/index-1fb7a9a6.js +4 -4
  239. package/dist/esm/index.js +4 -471
  240. package/dist/esm/index.js.map +1 -1
  241. package/dist/esm/loader.js +1 -1
  242. package/dist/esm/native.js +1 -1
  243. package/dist/esm/nv-alert.entry.js +5 -5
  244. package/dist/esm/nv-alert.entry.js.map +1 -1
  245. package/dist/esm/nv-avatar.entry.js +1 -1
  246. package/dist/esm/nv-badge_2.entry.js +17 -8
  247. package/dist/esm/nv-badge_2.entry.js.map +1 -1
  248. package/dist/esm/nv-button.entry.js +1 -1
  249. package/dist/esm/nv-calendar.entry.js +841 -842
  250. package/dist/esm/nv-calendar.entry.js.map +1 -1
  251. package/dist/esm/nv-datagrid.entry.js +376 -39
  252. package/dist/esm/nv-datagrid.entry.js.map +1 -1
  253. package/dist/esm/nv-dialog.entry.js +18 -12
  254. package/dist/esm/nv-dialog.entry.js.map +1 -1
  255. package/dist/esm/nv-dialogfooter_2.entry.js +1 -1
  256. package/dist/esm/nv-fielddate.entry.js +8 -17
  257. package/dist/esm/nv-fielddate.entry.js.map +1 -1
  258. package/dist/esm/nv-fielddaterange.entry.js +26 -28
  259. package/dist/esm/nv-fielddaterange.entry.js.map +1 -1
  260. package/dist/esm/nv-fielddropdown.entry.js +12 -5
  261. package/dist/esm/nv-fielddropdown.entry.js.map +1 -1
  262. package/dist/esm/nv-fielddropdownitem.entry.js +1 -1
  263. package/dist/esm/nv-fieldmultiselect.entry.js +10 -4
  264. package/dist/esm/nv-fieldmultiselect.entry.js.map +1 -1
  265. package/dist/esm/nv-fieldnumber.entry.js +8 -4
  266. package/dist/esm/nv-fieldnumber.entry.js.map +1 -1
  267. package/dist/esm/nv-fieldpassword.entry.js +8 -4
  268. package/dist/esm/nv-fieldpassword.entry.js.map +1 -1
  269. package/dist/esm/nv-fieldradio.entry.js +3 -3
  270. package/dist/esm/nv-fieldselect.entry.js +10 -6
  271. package/dist/esm/nv-fieldselect.entry.js.map +1 -1
  272. package/dist/esm/nv-fieldtext.entry.js +8 -4
  273. package/dist/esm/nv-fieldtext.entry.js.map +1 -1
  274. package/dist/esm/nv-fieldtextarea.entry.js +8 -4
  275. package/dist/esm/nv-fieldtextarea.entry.js.map +1 -1
  276. package/dist/esm/nv-fieldtime.entry.js +15 -12
  277. package/dist/esm/nv-fieldtime.entry.js.map +1 -1
  278. package/dist/esm/nv-icon.entry.js +3 -3
  279. package/dist/esm/nv-icon.entry.js.map +1 -1
  280. package/dist/esm/nv-iconbutton_2.entry.js +2 -2
  281. package/dist/esm/nv-menu.entry.js +3 -1
  282. package/dist/esm/nv-menu.entry.js.map +1 -1
  283. package/dist/esm/nv-menuitem.entry.js +1 -1
  284. package/dist/esm/nv-popover.entry.js +1 -1
  285. package/dist/esm/nv-row.entry.js +1 -1
  286. package/dist/esm/nv-stack.entry.js +1 -1
  287. package/dist/esm/nv-table.entry.js +2 -2
  288. package/dist/esm/nv-table.entry.js.map +1 -1
  289. package/dist/esm/nv-toggle.entry.js +2 -2
  290. package/dist/esm/nv-tooltip.entry.js +1 -1
  291. package/dist/native/index.esm.js +1 -1
  292. package/dist/native/index.esm.js.map +1 -1
  293. package/dist/native/native.css +1 -1
  294. package/dist/native/native.esm.js +1 -1
  295. package/dist/native/native.esm.js.map +1 -1
  296. package/dist/native/{p-b094296d.entry.js → p-08a75cfa.entry.js} +2 -2
  297. package/dist/native/{p-d5cbf5c8.entry.js → p-14c07207.entry.js} +2 -2
  298. package/dist/native/p-1da72182.entry.js +2 -0
  299. package/dist/native/p-1da72182.entry.js.map +1 -0
  300. package/dist/native/p-2523eead.entry.js +2 -0
  301. package/dist/native/p-2523eead.entry.js.map +1 -0
  302. package/dist/native/p-3953464e.entry.js +7 -0
  303. package/dist/native/p-3953464e.entry.js.map +1 -0
  304. package/dist/native/{p-701b5557.entry.js → p-3b7ef609.entry.js} +2 -2
  305. package/dist/native/{p-63e6aed3.entry.js → p-3cd77d82.entry.js} +2 -2
  306. package/dist/native/p-3cd77d82.entry.js.map +1 -0
  307. package/dist/native/p-470588c2.entry.js +13 -0
  308. package/dist/native/p-470588c2.entry.js.map +1 -0
  309. package/dist/native/p-49cac014.entry.js +2 -0
  310. package/dist/native/p-49cac014.entry.js.map +1 -0
  311. package/dist/native/p-4d164ed6.entry.js +2 -0
  312. package/dist/native/p-4d164ed6.entry.js.map +1 -0
  313. package/dist/native/p-4e635fa7.entry.js +2 -0
  314. package/dist/native/p-4e635fa7.entry.js.map +1 -0
  315. package/dist/native/p-5d21532a.entry.js +2 -0
  316. package/dist/native/p-5d21532a.entry.js.map +1 -0
  317. package/dist/native/{p-39bb95ff.entry.js → p-615947e7.entry.js} +2 -2
  318. package/dist/native/{p-bad11367.entry.js → p-656c56f0.entry.js} +2 -2
  319. package/dist/native/p-656c56f0.entry.js.map +1 -0
  320. package/dist/native/{p-fa77a591.entry.js → p-7042ba8a.entry.js} +2 -2
  321. package/dist/native/p-7e154bfd.entry.js +2 -0
  322. package/dist/native/p-7e154bfd.entry.js.map +1 -0
  323. package/dist/native/p-7eba904e.entry.js +2 -0
  324. package/dist/native/p-7eba904e.entry.js.map +1 -0
  325. package/dist/native/{p-6b348684.entry.js → p-7fd4d13d.entry.js} +2 -2
  326. package/dist/native/{p-fb5bddba.entry.js → p-90e6d9dd.entry.js} +2 -2
  327. package/dist/native/p-ae7ab110.entry.js +2 -0
  328. package/dist/native/p-ae7ab110.entry.js.map +1 -0
  329. package/dist/native/{p-f85aca27.entry.js → p-b8b6875d.entry.js} +2 -2
  330. package/dist/native/p-b94d9f0b.entry.js +2 -0
  331. package/dist/native/p-b94d9f0b.entry.js.map +1 -0
  332. package/dist/native/p-c0f79bac.entry.js +2 -0
  333. package/dist/native/p-c0f79bac.entry.js.map +1 -0
  334. package/dist/native/{p-6ff228da.entry.js → p-c67186f8.entry.js} +2 -2
  335. package/dist/native/{p-eee01062.entry.js → p-c71c6f23.entry.js} +2 -2
  336. package/dist/native/p-d9a52884.entry.js +2 -0
  337. package/dist/native/p-d9a52884.entry.js.map +1 -0
  338. package/dist/native/{p-d7a76400.entry.js → p-efe6a46c.entry.js} +2 -2
  339. package/dist/native/p-f2ef6771.entry.js +2 -0
  340. package/dist/native/p-f5f68992.entry.js +2 -0
  341. package/dist/native/p-f5f68992.entry.js.map +1 -0
  342. package/dist/native/{p-59768ee5.js → p-f85c08f1.js} +2 -2
  343. package/dist/native/p-f85c08f1.js.map +1 -0
  344. package/dist/native/p-fc97f071.entry.js +2 -0
  345. package/dist/native/p-fc97f071.entry.js.map +1 -0
  346. package/dist/types/components/nv-alert/nv-alert.d.ts +1 -1
  347. package/dist/types/components/nv-badge/nv-badge.d.ts +11 -3
  348. package/dist/types/components/nv-calendar/nv-calendar.d.ts +69 -107
  349. package/dist/types/components/nv-calendar/nv-calendar.utils.d.ts +60 -0
  350. package/dist/types/components/nv-calendar/test/nv-calendar.utils.test.d.ts +1 -0
  351. package/dist/types/components/nv-datagrid/nv-datagrid.d.ts +47 -10
  352. package/dist/types/components/nv-dialog/nv-dialog.d.ts +4 -0
  353. package/dist/types/components/nv-fielddate/nv-fielddate.d.ts +6 -7
  354. package/dist/types/components/nv-fielddaterange/nv-fielddaterange.d.ts +13 -12
  355. package/dist/types/components/nv-fielddropdown/nv-fielddropdown.d.ts +4 -0
  356. package/dist/types/components/nv-fieldmultiselect/nv-fieldmultiselect.d.ts +4 -0
  357. package/dist/types/components/nv-fieldnumber/nv-fieldnumber.d.ts +4 -0
  358. package/dist/types/components/nv-fieldpassword/nv-fieldpassword.d.ts +4 -0
  359. package/dist/types/components/nv-fieldselect/nv-fieldselect.d.ts +4 -0
  360. package/dist/types/components/nv-fieldtext/nv-fieldtext.d.ts +4 -0
  361. package/dist/types/components/nv-fieldtextarea/nv-fieldtextarea.d.ts +4 -0
  362. package/dist/types/components/nv-icon/nv-icons.d.ts +1 -1
  363. package/dist/types/components/nv-table/nv-table.d.ts +13 -2
  364. package/dist/types/components.d.ts +269 -116
  365. package/dist/types/index.d.ts +0 -2
  366. package/dist/types/utils/constants.d.ts +9 -0
  367. package/dist/vscode-data.json +221 -1587
  368. package/hydrate/index.js +1466 -1063
  369. package/hydrate/index.mjs +1466 -1063
  370. package/package.json +1 -1
  371. package/dist/cjs/constants-bcd6b2e2.js.map +0 -1
  372. package/dist/collection/interfaces/actionEvent.js +0 -2
  373. package/dist/collection/interfaces/actionEvent.js.map +0 -1
  374. package/dist/collection/interfaces/calendarShortcut.js +0 -2
  375. package/dist/collection/interfaces/calendarShortcut.js.map +0 -1
  376. package/dist/collection/interfaces/dateRange.js +0 -2
  377. package/dist/collection/interfaces/dateRange.js.map +0 -1
  378. package/dist/components/p-373926aa.js +0 -177
  379. package/dist/components/p-373926aa.js.map +0 -1
  380. package/dist/components/p-591730e7.js +0 -88
  381. package/dist/components/p-591730e7.js.map +0 -1
  382. package/dist/components/p-8348db09.js.map +0 -1
  383. package/dist/components/p-f331117c.js +0 -1133
  384. package/dist/components/p-f331117c.js.map +0 -1
  385. package/dist/esm/constants-98e2dcc2.js.map +0 -1
  386. package/dist/native/p-0ee428d5.entry.js +0 -2
  387. package/dist/native/p-0ee428d5.entry.js.map +0 -1
  388. package/dist/native/p-2691e02d.entry.js +0 -2
  389. package/dist/native/p-37f0210e.entry.js +0 -2
  390. package/dist/native/p-37f0210e.entry.js.map +0 -1
  391. package/dist/native/p-4a440970.entry.js +0 -2
  392. package/dist/native/p-4a440970.entry.js.map +0 -1
  393. package/dist/native/p-4ae26462.entry.js +0 -7
  394. package/dist/native/p-4ae26462.entry.js.map +0 -1
  395. package/dist/native/p-4d9c4618.entry.js +0 -2
  396. package/dist/native/p-4d9c4618.entry.js.map +0 -1
  397. package/dist/native/p-59768ee5.js.map +0 -1
  398. package/dist/native/p-59e0bd2b.entry.js +0 -2
  399. package/dist/native/p-59e0bd2b.entry.js.map +0 -1
  400. package/dist/native/p-5c00f092.entry.js +0 -2
  401. package/dist/native/p-5c00f092.entry.js.map +0 -1
  402. package/dist/native/p-63e6aed3.entry.js.map +0 -1
  403. package/dist/native/p-7f5eb2ac.entry.js +0 -2
  404. package/dist/native/p-7f5eb2ac.entry.js.map +0 -1
  405. package/dist/native/p-84a73e2a.entry.js +0 -2
  406. package/dist/native/p-84a73e2a.entry.js.map +0 -1
  407. package/dist/native/p-93dc2f47.entry.js +0 -2
  408. package/dist/native/p-93dc2f47.entry.js.map +0 -1
  409. package/dist/native/p-9a267f16.entry.js +0 -13
  410. package/dist/native/p-9a267f16.entry.js.map +0 -1
  411. package/dist/native/p-9d6431c7.entry.js +0 -2
  412. package/dist/native/p-9d6431c7.entry.js.map +0 -1
  413. package/dist/native/p-b2ce83ad.entry.js +0 -2
  414. package/dist/native/p-b2ce83ad.entry.js.map +0 -1
  415. package/dist/native/p-bad11367.entry.js.map +0 -1
  416. package/dist/native/p-e1a4f776.entry.js +0 -2
  417. package/dist/native/p-e1a4f776.entry.js.map +0 -1
  418. package/dist/native/p-e49bbd02.entry.js +0 -2
  419. package/dist/native/p-e49bbd02.entry.js.map +0 -1
  420. package/dist/native/p-f6bdc270.entry.js +0 -2
  421. package/dist/native/p-f6bdc270.entry.js.map +0 -1
  422. package/dist/types/interfaces/actionEvent.d.ts +0 -13
  423. package/dist/types/interfaces/calendarShortcut.d.ts +0 -17
  424. package/dist/types/interfaces/dateRange.d.ts +0 -13
  425. /package/dist/native/{p-b094296d.entry.js.map → p-08a75cfa.entry.js.map} +0 -0
  426. /package/dist/native/{p-d5cbf5c8.entry.js.map → p-14c07207.entry.js.map} +0 -0
  427. /package/dist/native/{p-701b5557.entry.js.map → p-3b7ef609.entry.js.map} +0 -0
  428. /package/dist/native/{p-39bb95ff.entry.js.map → p-615947e7.entry.js.map} +0 -0
  429. /package/dist/native/{p-fa77a591.entry.js.map → p-7042ba8a.entry.js.map} +0 -0
  430. /package/dist/native/{p-6b348684.entry.js.map → p-7fd4d13d.entry.js.map} +0 -0
  431. /package/dist/native/{p-fb5bddba.entry.js.map → p-90e6d9dd.entry.js.map} +0 -0
  432. /package/dist/native/{p-f85aca27.entry.js.map → p-b8b6875d.entry.js.map} +0 -0
  433. /package/dist/native/{p-6ff228da.entry.js.map → p-c67186f8.entry.js.map} +0 -0
  434. /package/dist/native/{p-eee01062.entry.js.map → p-c71c6f23.entry.js.map} +0 -0
  435. /package/dist/native/{p-d7a76400.entry.js.map → p-efe6a46c.entry.js.map} +0 -0
  436. /package/dist/native/{p-2691e02d.entry.js.map → p-f2ef6771.entry.js.map} +0 -0
@@ -1,13 +1,6 @@
1
1
  import { Host, h, } from "@stencil/core";
2
- import dayjs from "dayjs";
3
- import customParseFormat from "dayjs/plugin/customParseFormat";
4
- import utc from "dayjs/plugin/utc";
5
- import weekOfYear from "dayjs/plugin/weekOfYear";
6
2
  import { WEEK_ABBREVIATIONS, CUSTOM_DAY_NAMES, CUSTOM_MONTH_NAMES, } from "../../utils/constants";
7
- // Extend dayjs with plugins
8
- dayjs.extend(customParseFormat);
9
- dayjs.extend(utc);
10
- dayjs.extend(weekOfYear);
3
+ import { getWeekNumber, parseDate, isSameDate, formatDate, isSameOrAfter, isSameOrBefore, } from "./nv-calendar.utils";
11
4
  /**
12
5
  * @slot default - Child content of the component.
13
6
  * @slot actions - Child content of the component.
@@ -27,33 +20,12 @@ export class NvCalendar {
27
20
  */
28
21
  this.numberOfCalendars = 1;
29
22
  /**
30
- * Selected date (ISO string format)
31
- * ex: "2025-03-15"
32
- */
33
- this.singleValue = '';
34
- /**
35
- * Selected date range
36
- * format: { start: ISO string, end: ISO string }
37
- * ex: { start: "2025-03-15", end: "2025-03-20" }
38
- */
39
- this.rangeValue = '';
40
- /**
41
- * Minimum date for selection (ISO string format, ex: "2025-01-01")
42
- */
43
- this.min = '';
44
- /**
45
- * Maximum date for selection (ISO string format, ex: "2025-12-31")
46
- */
47
- this.max = '';
48
- /** Disabled dates (ISO string array)
49
- * @default '[]'
50
- */
51
- this.disabledDates = '';
52
- /** Locale for date formatting
23
+ * Locale for date formatting
53
24
  * @default 'en-BE'
54
25
  */
55
26
  this.locale = 'en-BE';
56
- /** Date format (ex: 'YYYY-MM-DD', 'DD-MM-YYYY', etc.)
27
+ /**
28
+ * Date format (ex: 'YYYY-MM-DD', 'DD-MM-YYYY', etc.)
57
29
  * @default 'YYYY-MM-DD'
58
30
  * @note If the date format is in UTC mode, the date will be displayed in UTC time.
59
31
  * @note If the date format is not in UTC mode, the date will be displayed in the local time.
@@ -71,40 +43,483 @@ export class NvCalendar {
71
43
  this.selectionType = 'single';
72
44
  /**
73
45
  * Show action buttons
74
- * @default false
75
46
  */
76
47
  this.showActions = false;
77
- /**
78
- * Custom actions to display in the footer
79
- * JSON array of objects with the following properties:
80
- * - label: string
81
- * - onClick: function
82
- * @default '[]'
83
- */
84
- this.shortcuts = '[]';
85
48
  /** Cache for parsed disabled dates */
86
49
  this.parsedDisabledDates = [];
87
- /** Selected date */
50
+ //#endregion PROPERTIES
51
+ /****************************************************************************/
52
+ //#region STATE
53
+ this.currentDate = null;
88
54
  this.selectedDate = null;
89
- /** Start date */
90
55
  this.startDate = null;
91
- /** End date */
92
56
  this.endDate = null;
93
57
  /** List of formatted months for the selector */
94
58
  this.months = [];
59
+ /**
60
+ * Change the displayed month
61
+ * @param {number} offset - Month offset (-1 for previous, 1 for next)
62
+ */
63
+ this.changeMonth = (offset) => {
64
+ const newDate = new Date(this.currentDate);
65
+ // Ensure we only move by one month at a time
66
+ newDate.setUTCMonth(newDate.getUTCMonth() + offset);
67
+ // Add the appropriate animation class
68
+ const containers = this.el.querySelectorAll('.calendar-grid');
69
+ containers.forEach(container => {
70
+ // Remove existing animation classes
71
+ container.classList.remove('slide-left', 'slide-right');
72
+ // Add the new animation class
73
+ const animationClass = offset > 0 ? 'slide-left' : 'slide-right';
74
+ container.classList.add(animationClass);
75
+ // Remove the class after the animation
76
+ setTimeout(() => {
77
+ container.classList.remove(animationClass);
78
+ }, 300); // 300ms corresponds to $slide-duration in the SCSS
79
+ });
80
+ this.currentDate = newDate;
81
+ };
82
+ /**
83
+ * Handles date selection based on the mode
84
+ * @param {Date} date - Selected date
85
+ */
86
+ this.handleDateSelection = (date) => {
87
+ if (this.isDateDisabled(date)) {
88
+ return;
89
+ }
90
+ if (this.selectionType === 'single') {
91
+ this.handleSingleSelection(date);
92
+ }
93
+ else {
94
+ this.handleRangeSelection(date);
95
+ }
96
+ };
97
+ /**
98
+ * Handles single date selection
99
+ * @param {Date} date - Selected date
100
+ */
101
+ this.handleSingleSelection = (date) => {
102
+ if (!date)
103
+ return;
104
+ const formattedDate = formatDate(date, { dateFormat: this.dateFormat });
105
+ this.selectedDate = date;
106
+ this.singleDateChange.emit(formattedDate);
107
+ };
108
+ /**
109
+ * Handles range date selection
110
+ * @param {Date} date - Selected date
111
+ */
112
+ this.handleRangeSelection = (date) => {
113
+ if (!this.startDate || (this.startDate && this.endDate)) {
114
+ this.startDate = date;
115
+ this.endDate = null;
116
+ }
117
+ else {
118
+ this.endDate = date;
119
+ if (this.startDate > this.endDate) {
120
+ [this.startDate, this.endDate] = [this.endDate, this.startDate];
121
+ }
122
+ this.rangeDateChange.emit({
123
+ start: formatDate(this.startDate, { dateFormat: this.dateFormat }),
124
+ end: formatDate(this.endDate, { dateFormat: this.dateFormat }),
125
+ });
126
+ }
127
+ };
128
+ /**
129
+ * Checks if a date is disabled.
130
+ * Disabled if:
131
+ * - The date is before min (if defined)
132
+ * - The date is after max (if defined)
133
+ * - The date is in the disabledDates array
134
+ * @param {Date} date - Date to check
135
+ * @returns {boolean} true if the date is disabled
136
+ */
137
+ this.isDateDisabled = (date) => {
138
+ if (!date)
139
+ return true;
140
+ // Minimum bound check
141
+ if (this.min) {
142
+ const minDate = parseDate(this.min, this.dateFormat);
143
+ if (minDate && date < minDate) {
144
+ return true;
145
+ }
146
+ }
147
+ // Maximum bound check
148
+ if (this.max) {
149
+ const maxDate = parseDate(this.max, this.dateFormat);
150
+ if (maxDate && date > maxDate) {
151
+ return true;
152
+ }
153
+ }
154
+ // Check disabled dates
155
+ return this.parsedDisabledDates.some(disabledDate => isSameDate(date, disabledDate, { isUTCMode: this.isUTCMode }));
156
+ };
157
+ /**
158
+ * Checks if a date is in the selected range
159
+ * @param {Date} date - Date to check
160
+ * @returns {boolean} true if the date is in the range
161
+ */
162
+ this.isDateInRange = (date) => {
163
+ if (!date || !this.startDate || !this.endDate)
164
+ return false;
165
+ const checkDate = parseDate(date, this.dateFormat);
166
+ const startDate = parseDate(this.startDate, this.dateFormat);
167
+ const endDate = parseDate(this.endDate, this.dateFormat);
168
+ // Verify if startDate and endDate are valid
169
+ if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {
170
+ return false;
171
+ }
172
+ // Verify that startDate is before endDate (additional security)
173
+ if (startDate > endDate)
174
+ return false;
175
+ // Comparison based only on the date (year, month, day)
176
+ return (isSameOrAfter(checkDate, startDate, { isUTCMode: this.isUTCMode }) &&
177
+ isSameOrBefore(checkDate, endDate, { isUTCMode: this.isUTCMode }));
178
+ };
179
+ /**
180
+ * Retrieves the localized day names
181
+ * @returns {string[]} Array of short day names
182
+ */
183
+ this.getDayNames = () => {
184
+ // If we have custom day names for this locale
185
+ if (CUSTOM_DAY_NAMES[this.locale]) {
186
+ const days = [...CUSTOM_DAY_NAMES[this.locale]];
187
+ // Reorganize the days based on the first day of the week
188
+ const firstDays = days.slice(0, this.firstDayOfWeek);
189
+ const remainingDays = days.slice(this.firstDayOfWeek);
190
+ return [...remainingDays, ...firstDays];
191
+ }
192
+ // Otherwise, use the default behavior
193
+ const formatter = new Intl.DateTimeFormat(this.locale, {
194
+ weekday: 'short',
195
+ });
196
+ const days = [...Array(7)].map((_, i) => formatter.format(new Date(2023, 0, i + 1)).toUpperCase());
197
+ // Reorganize the days based on the first day of the week
198
+ const firstDays = days.slice(0, this.firstDayOfWeek);
199
+ const remainingDays = days.slice(this.firstDayOfWeek);
200
+ return [...remainingDays, ...firstDays];
201
+ };
202
+ /**
203
+ * Generates the days of the current month
204
+ * @param {number} offset - Month offset (0 by default)
205
+ * @param {number} totalCalendars - Number of calendars to display (1 by default)
206
+ * @returns {Array<{ dayOfMonth: number | null, date: Date | null, isSelected: boolean, isDisabled: boolean }>} Array of formatted days
207
+ */
208
+ this.getDaysInMonth = (offset = 0, totalCalendars = 1) => {
209
+ const year = this.currentDate.getUTCFullYear();
210
+ const month = this.currentDate.getUTCMonth() + offset;
211
+ const firstDay = new Date(Date.UTC(year, month, 1));
212
+ const lastDay = new Date(Date.UTC(year, month + 1, 0));
213
+ const days = [];
214
+ // Correct calculation of offset for previous month days
215
+ // Use getUTCDay to stay consistent with UTC timezone
216
+ const dayOfWeekIndex = firstDay.getUTCDay(); // 0 = Sunday, 1 = Monday, etc.
217
+ // Adjust based on firstDayOfWeek (if week starts on Monday, offset is different)
218
+ const offsetDays = (dayOfWeekIndex - this.firstDayOfWeek + 7) % 7;
219
+ // Add the days of the previous month for the first calendar
220
+ if (offset === 0 && offsetDays > 0) {
221
+ const prevMonthLastDay = new Date(Date.UTC(year, month, 0)).getUTCDate();
222
+ for (let i = offsetDays; i > 0; i--) {
223
+ const date = new Date(Date.UTC(year, month - 1, prevMonthLastDay - i + 1));
224
+ days.push({
225
+ dayOfMonth: date.getUTCDate(),
226
+ date,
227
+ isCurrentMonth: false,
228
+ isDisabled: this.isDateDisabled(date),
229
+ });
230
+ }
231
+ }
232
+ // Add the days of the current month
233
+ for (let i = 1; i <= lastDay.getUTCDate(); i++) {
234
+ const date = new Date(Date.UTC(year, month, i));
235
+ days.push({
236
+ dayOfMonth: i,
237
+ date,
238
+ isCurrentMonth: true,
239
+ isDisabled: this.isDateDisabled(date),
240
+ });
241
+ }
242
+ // Add the days of the next month only for the last calendar
243
+ if (offset === totalCalendars - 1) {
244
+ const nextMonthDaysNeeded = 7 - (days.length % 7 || 7);
245
+ for (let i = 1; i <= nextMonthDaysNeeded; i++) {
246
+ const date = new Date(Date.UTC(year, month + 1, i));
247
+ days.push({
248
+ dayOfMonth: i,
249
+ date,
250
+ isCurrentMonth: false,
251
+ isDisabled: this.isDateDisabled(date),
252
+ });
253
+ }
254
+ }
255
+ return days;
256
+ };
257
+ /** Initializes the list of formatted months according to the locale */
258
+ this.initializeMonths = () => {
259
+ // If we have custom month names for this locale
260
+ if (CUSTOM_MONTH_NAMES[this.locale]) {
261
+ this.months = CUSTOM_MONTH_NAMES[this.locale].map((label, value) => ({
262
+ value,
263
+ label,
264
+ }));
265
+ return;
266
+ }
267
+ // Otherwise, use the default behavior
268
+ const formatter = new Intl.DateTimeFormat(this.locale, { month: 'short' });
269
+ this.months = Array.from({ length: 12 }, (_, i) => ({
270
+ value: i,
271
+ label: formatter.format(new Date(2000, i, 1)).toUpperCase(),
272
+ }));
273
+ };
274
+ /**
275
+ * Retrieves the localized abbreviation for "week"
276
+ * @returns {string} Localized abbreviation for "week"
277
+ */
278
+ this.getLocalizedWeekText = () => {
279
+ return WEEK_ABBREVIATIONS[this.locale] || 'W';
280
+ };
281
+ /**
282
+ * Handles month change in the selector
283
+ * @param {Event} event - Month change event
284
+ * @param {number} calendarOffset - Calendar offset (0 by default)
285
+ */
286
+ this.handleMonthChange = (event, calendarOffset = 0) => {
287
+ const select = event.target;
288
+ const selectedMonth = parseInt(select.value, 10);
289
+ const currentMonth = this.currentDate.getUTCMonth();
290
+ // Calculate the difference considering the calendar offset
291
+ const monthDiff = selectedMonth - ((currentMonth + calendarOffset) % 12);
292
+ const newDate = new Date(this.currentDate);
293
+ newDate.setUTCMonth(newDate.getUTCMonth() + monthDiff);
294
+ this.currentDate = newDate;
295
+ };
296
+ /**
297
+ * Handles year change in the numeric entry
298
+ * @param {Event} event - Year change event
299
+ * @param {number} calendarOffset - Calendar offset (0 by default)
300
+ */
301
+ this.handleYearChange = (event, calendarOffset = 0) => {
302
+ const input = event.target;
303
+ const year = parseInt(input.value, 10);
304
+ if (!isNaN(year) && year >= 1900 && year <= 2100) {
305
+ const newDate = new Date(this.currentDate);
306
+ newDate.setUTCFullYear(year);
307
+ newDate.setUTCMonth(newDate.getUTCMonth() + calendarOffset);
308
+ this.currentDate = newDate;
309
+ }
310
+ };
311
+ /**
312
+ * Handles week selection
313
+ * @param {Date[]} weekDays - Selected week days
314
+ * @param {number} calendarIndex - Calendar index from which the selection is made
315
+ */
316
+ this.handleWeekSelection = (weekDays, calendarIndex) => {
317
+ if (this.selectionType !== 'range')
318
+ return;
319
+ const allDays = this.getDaysInMonth(calendarIndex, this.numberOfCalendars);
320
+ const weekStart = weekDays[0];
321
+ const weekEnd = weekDays[weekDays.length - 1];
322
+ if (!weekStart || !weekEnd)
323
+ return;
324
+ const selectedWeekDays = allDays.filter(day => day.date && day.date >= weekStart && day.date <= weekEnd);
325
+ const validDays = selectedWeekDays.filter(day => !this.isDateDisabled(day.date));
326
+ if (validDays.length > 0) {
327
+ this.startDate = validDays[0].date;
328
+ this.endDate = validDays[validDays.length - 1].date;
329
+ this.rangeDateChange.emit({
330
+ start: formatDate(this.startDate, { dateFormat: this.dateFormat }),
331
+ end: formatDate(this.endDate, { dateFormat: this.dateFormat }),
332
+ });
333
+ }
334
+ };
335
+ /**
336
+ * Checks if a date corresponds to today
337
+ * @param {Date} date - Date to check
338
+ * @returns {boolean} true if the date is today
339
+ */
340
+ this.isToday = (date) => {
341
+ const today = new Date();
342
+ return (date.getDate() === today.getDate() &&
343
+ date.getMonth() === today.getMonth() &&
344
+ date.getFullYear() === today.getFullYear());
345
+ };
346
+ /**
347
+ * Parse and cache the disabled dates
348
+ * @description Parse and cache the disabled dates
349
+ */
350
+ this.parseDisabledDates = () => {
351
+ if (!this.disabledDates) {
352
+ this.parsedDisabledDates = [];
353
+ return;
354
+ }
355
+ try {
356
+ this.parsedDisabledDates = this.disabledDates
357
+ .map(date => parseDate(date, this.dateFormat))
358
+ .filter(date => date !== null);
359
+ }
360
+ catch (error) {
361
+ console.error('Error parsing disabled dates:', error);
362
+ this.parsedDisabledDates = [];
363
+ }
364
+ };
365
+ /**
366
+ * Applies a shortcut selection
367
+ * @param {Object} shortcut - Shortcut to apply
368
+ * @param {string | Date} shortcut.singleValue - Selected date value
369
+ * @param {Object} shortcut.rangeValue - Start and end date values
370
+ * @param {string | Date} shortcut.rangeValue.start - Start date value
371
+ * @param {string | Date} shortcut.rangeValue.end - End date value
372
+ * @param {string} shortcut.label - Label
373
+ */
374
+ this.applyShortcut = (shortcut) => {
375
+ this.selectedDate = null;
376
+ this.startDate = null;
377
+ this.endDate = null;
378
+ if (shortcut.singleValue) {
379
+ const newDate = parseDate(shortcut.singleValue, this.dateFormat);
380
+ this.selectedDate = newDate;
381
+ this.singleDateChange.emit(formatDate(newDate, { dateFormat: this.dateFormat }));
382
+ this.singleValue = formatDate(newDate, { dateFormat: this.dateFormat });
383
+ if (!this.showActions) {
384
+ const event = new CustomEvent('closePopover', {
385
+ bubbles: true,
386
+ composed: true,
387
+ });
388
+ this.el.dispatchEvent(event);
389
+ }
390
+ this.forceCalendarUpdate(newDate);
391
+ }
392
+ else {
393
+ const start = parseDate(shortcut.rangeValue.start, this.dateFormat);
394
+ const end = parseDate(shortcut.rangeValue.end, this.dateFormat);
395
+ this.startDate = start;
396
+ this.endDate = end;
397
+ this.rangeDateChange.emit({
398
+ start: formatDate(start, { dateFormat: this.dateFormat }),
399
+ end: formatDate(end, { dateFormat: this.dateFormat }),
400
+ });
401
+ this.rangeValue = {
402
+ start: formatDate(start, { dateFormat: this.dateFormat }),
403
+ end: formatDate(end, { dateFormat: this.dateFormat }),
404
+ };
405
+ if (!this.showActions) {
406
+ const event = new CustomEvent('closePopover', {
407
+ bubbles: true,
408
+ composed: true,
409
+ });
410
+ this.el.dispatchEvent(event);
411
+ }
412
+ this.forceCalendarUpdate(end);
413
+ }
414
+ };
415
+ /**
416
+ * Method to force the complete calendar update (and fix the persistent hover problem)
417
+ * @param {Date} newDate - Date to force
418
+ */
419
+ this.forceCalendarUpdate = newDate => {
420
+ this.currentDate = new Date(newDate);
421
+ this.currentDate = new Date(this.currentDate); // Force a re-render
422
+ // Reset visually the hover/touch effect
423
+ requestAnimationFrame(() => {
424
+ const days = document.querySelectorAll('.day');
425
+ days.forEach(el => {
426
+ el.classList.remove('hover', 'active', 'touched');
427
+ el.style.pointerEvents = 'none';
428
+ });
429
+ // Add specific touch handling (for mobile)
430
+ document.body.addEventListener('touchstart', this.clearTouchState, {
431
+ passive: true,
432
+ });
433
+ // Reset the touch state after 50ms
434
+ setTimeout(() => {
435
+ days.forEach(el => {
436
+ el.style.pointerEvents = '';
437
+ });
438
+ }, 50);
439
+ });
440
+ };
441
+ /**
442
+ * Function to reset the touch effect (Mobile fix)
443
+ */
444
+ this.clearTouchState = () => {
445
+ document.querySelectorAll('.day').forEach(el => {
446
+ el.classList.remove('touched');
447
+ });
448
+ // Remove the listener after the first interaction
449
+ document.body.removeEventListener('touchstart', this.clearTouchState);
450
+ };
451
+ /**
452
+ * Handles month change with an offset
453
+ * @param {number} direction - Direction (-1 for previous, 1 for next)
454
+ * @returns {Function} Change month handler
455
+ */
456
+ this.getChangeMonthHandler = (direction) => {
457
+ return () => this.changeMonth(direction);
458
+ };
459
+ /**
460
+ * Handles month change from an event (ex: dropdown)
461
+ * @param {number} offset - Month offset (0 by default)
462
+ * @returns {Function} Change month handler
463
+ */
464
+ this.getHandleMonthChange = (offset) => {
465
+ return (event) => this.handleMonthChange(event, offset);
466
+ };
467
+ /**
468
+ * Handles year change from an event (ex: dropdown)
469
+ * @param {number} offset - Year offset (0 by default)
470
+ * @returns {Function} Change year handler
471
+ */
472
+ this.getHandleYearChange = (offset) => {
473
+ return (event) => this.handleYearChange(event, offset);
474
+ };
475
+ /**
476
+ * Handles day click
477
+ * @param {Date} date - Date to handle
478
+ * @param {boolean} isDisabled - Whether the date is disabled
479
+ * @returns {Function} Day click handler
480
+ */
481
+ this.getDayClickHandler = (date, isDisabled) => {
482
+ return isDisabled ? undefined : () => this.handleDateSelection(date);
483
+ };
484
+ /**
485
+ * Handles shortcut selection
486
+ * @param {Object} shortcut - Shortcut to handle
487
+ * @param {string | Date} shortcut.singleValue - Selected date value
488
+ * @param {Object} shortcut.rangeValue - Start and end date values
489
+ * @param {string | Date} shortcut.rangeValue.start - Start date value
490
+ * @param {string | Date} shortcut.rangeValue.end - End date value
491
+ * @param {string} shortcut.label - Label
492
+ * @returns {Function} Shortcut selection handler
493
+ */
494
+ this.getShortcutHandler = (shortcut) => {
495
+ return () => this.applyShortcut(shortcut);
496
+ };
497
+ /**
498
+ * Handles week selection
499
+ * @param {Date[]} dates - Dates to handle
500
+ * @param {number} index - Calendar index
501
+ * @returns {Function} Week selection handler
502
+ */
503
+ this.getWeekSelectionHandler = (dates, index) => {
504
+ return () => {
505
+ if (this.selectionType === 'range') {
506
+ this.handleWeekSelection(dates, index);
507
+ }
508
+ };
509
+ };
95
510
  /**
96
511
  * Resets the current selection
97
512
  */
98
513
  this.resetSelection = () => {
99
514
  if (this.selectionType === 'single') {
100
515
  this.selectedDate = null;
101
- this.singleValue = '';
516
+ this.singleValue = null;
102
517
  this.singleDateChange.emit('');
103
518
  }
104
519
  else {
105
520
  this.startDate = null;
106
521
  this.endDate = null;
107
- this.rangeValue = '';
522
+ this.rangeValue = null;
108
523
  this.rangeDateChange.emit({ start: '', end: '' });
109
524
  }
110
525
  };
@@ -113,7 +528,9 @@ export class NvCalendar {
113
528
  */
114
529
  this.confirmSelection = () => {
115
530
  if (this.selectionType === 'single' && this.selectedDate) {
116
- const dateStr = this.formatDate(this.selectedDate);
531
+ const dateStr = formatDate(this.selectedDate, {
532
+ dateFormat: this.dateFormat,
533
+ });
117
534
  this.singleDateChange.emit(dateStr);
118
535
  this.singleValue = dateStr;
119
536
  const event = new CustomEvent('closePopover', {
@@ -126,13 +543,13 @@ export class NvCalendar {
126
543
  this.startDate &&
127
544
  this.endDate) {
128
545
  this.rangeDateChange.emit({
129
- start: this.formatDate(this.startDate),
130
- end: this.formatDate(this.endDate),
131
- });
132
- this.rangeValue = JSON.stringify({
133
- start: this.formatDate(this.startDate),
134
- end: this.formatDate(this.endDate),
546
+ start: formatDate(this.startDate, { dateFormat: this.dateFormat }),
547
+ end: formatDate(this.endDate, { dateFormat: this.dateFormat }),
135
548
  });
549
+ this.rangeValue = {
550
+ start: formatDate(this.startDate, { dateFormat: this.dateFormat }),
551
+ end: formatDate(this.endDate, { dateFormat: this.dateFormat }),
552
+ };
136
553
  const event = new CustomEvent('closePopover', {
137
554
  bubbles: true,
138
555
  composed: true,
@@ -140,353 +557,114 @@ export class NvCalendar {
140
557
  this.el.dispatchEvent(event);
141
558
  }
142
559
  };
143
- }
144
- //#endregion EVENTS
145
- /****************************************************************************/
146
- //#region LIFECYCLE
147
- componentWillLoad() {
148
- this.parseDisabledDates();
149
- if (this.selectionType === 'single' && this.singleValue) {
150
- this.selectedDate = this.parseDate(this.singleValue);
151
- this.currentDate = this.selectedDate;
152
- }
153
- else if (this.selectionType === 'range' && this.rangeValue) {
154
- try {
155
- let parsed;
156
- if (typeof this.rangeValue === 'string') {
157
- parsed = JSON.parse(this.rangeValue);
158
- }
159
- else {
160
- parsed = this.rangeValue;
161
- }
162
- if (parsed.start && parsed.end) {
163
- this.startDate = this.parseDate(parsed.start);
164
- this.endDate = this.parseDate(parsed.end);
165
- this.currentDate = this.startDate;
166
- if (this.startDate && this.endDate && this.startDate > this.endDate) {
167
- console.warn(`Warning: startDate (${this.formatDate(this.startDate)}) is after endDate (${this.formatDate(this.endDate)})`);
168
- // [this.startDate, this.endDate] = [this.endDate, this.startDate];
169
- throw new Error('startDate cannot be after endDate');
170
- }
171
- }
172
- }
173
- catch (error) {
174
- console.error('Invalid JSON for rangeValue:', error);
175
- }
176
- }
177
- else {
178
- this.currentDate = new Date();
179
- }
180
- this.initializeMonths();
181
- }
182
- // componentDidLoad() {
183
- // if (this.rangeValue) {
184
- // this.onRangeValueChange(this.rangeValue);
185
- // }
186
- // }
187
- //#endregion LIFECYCLE
188
- /****************************************************************************/
189
- //#region METHODS
190
- /**
191
- * Change the displayed month
192
- * @param {number} offset - Month offset (-1 for previous, 1 for next)
193
- */
194
- changeMonth(offset) {
195
- const newDate = new Date(this.currentDate);
196
- // Ensure we only move by one month at a time
197
- newDate.setUTCMonth(newDate.getUTCMonth() + offset);
198
- // Add the appropriate animation class
199
- const containers = this.el.querySelectorAll('.calendar-grid');
200
- containers.forEach(container => {
201
- // Remove existing animation classes
202
- container.classList.remove('slide-left', 'slide-right');
203
- // Add the new animation class
204
- const animationClass = offset > 0 ? 'slide-left' : 'slide-right';
205
- container.classList.add(animationClass);
206
- // Remove the class after the animation
207
- setTimeout(() => {
208
- container.classList.remove(animationClass);
209
- }, 300); // 300ms corresponds to $slide-duration in the SCSS
210
- });
211
- this.currentDate = newDate;
212
- }
213
- /**
214
- * Handles date selection based on the mode
215
- * @param {Date} date - Selected date
216
- */
217
- handleDateSelection(date) {
218
- if (this.isDateDisabled(date)) {
219
- return;
220
- }
221
- if (this.selectionType === 'single') {
222
- this.handleSingleSelection(date);
223
- }
224
- else {
225
- this.handleRangeSelection(date);
226
- }
227
- }
228
- /**
229
- * Handles single date selection
230
- * @param {Date} date - Selected date
231
- */
232
- handleSingleSelection(date) {
233
- if (!date)
234
- return;
235
- const formattedDate = this.formatDate(date);
236
- this.selectedDate = date;
237
- this.singleDateChange.emit(formattedDate);
238
- }
239
- /**
240
- * Handles range date selection
241
- * @param {Date} date - Selected date
242
- */
243
- handleRangeSelection(date) {
244
- if (!this.startDate || (this.startDate && this.endDate)) {
245
- this.startDate = date;
246
- this.endDate = null;
247
- }
248
- else {
249
- this.endDate = date;
250
- if (this.startDate > this.endDate) {
251
- [this.startDate, this.endDate] = [this.endDate, this.startDate];
252
- }
253
- this.rangeDateChange.emit({
254
- start: this.formatDate(this.startDate),
255
- end: this.formatDate(this.endDate),
256
- });
257
- }
258
- }
259
- /**
260
- * Calculates the ISO week number
261
- * @param {Date} date - Date to calculate
262
- * @returns {number} Week number
263
- */
264
- getWeekNumber(date) {
265
- const startOfYear = new Date(date.getFullYear(), 0, 1);
266
- const pastDaysOfYear = (date.getTime() - startOfYear.getTime()) / 86400000;
267
- return Math.ceil((pastDaysOfYear + startOfYear.getDay() + 1) / 7);
268
- }
269
- /**
270
- * Checks if a date is disabled.
271
- * Disabled if:
272
- * - The date is before min (if defined)
273
- * - The date is after max (if defined)
274
- * - The date is in the disabledDates array
275
- * @param {Date} date - Date to check
276
- * @returns {boolean} true if the date is disabled
277
- */
278
- isDateDisabled(date) {
279
- if (!date)
280
- return true;
281
- // Minimum bound check
282
- if (this.min) {
283
- const minDate = this.parseDate(this.min);
284
- if (minDate && date < minDate) {
285
- return true;
286
- }
287
- }
288
- // Maximum bound check
289
- if (this.max) {
290
- const maxDate = this.parseDate(this.max);
291
- if (maxDate && date > maxDate) {
292
- return true;
293
- }
294
- }
295
- // Check disabled dates
296
- return this.parsedDisabledDates.some(disabledDate => this.isSameDate(date, disabledDate));
297
- }
298
- /**
299
- * Checks if a date is in the selected range
300
- * @param {Date} date - Date to check
301
- * @returns {boolean} true if the date is in the range
302
- */
303
- isDateInRange(date) {
304
- if (!date || !this.startDate || !this.endDate)
305
- return false;
306
- const checkDate = this.parseDate(date);
307
- const startDate = this.parseDate(this.startDate);
308
- const endDate = this.parseDate(this.endDate);
309
- // Verify if startDate and endDate are valid
310
- if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {
311
- return false;
312
- }
313
- // Verify that startDate is before endDate (additional security)
314
- if (startDate > endDate)
315
- return false;
316
- // Comparison based only on the date (year, month, day)
317
- return (this.isSameOrAfter(checkDate, startDate) &&
318
- this.isSameOrBefore(checkDate, endDate));
319
- }
320
- /**
321
- * Retrieves the localized day names
322
- * @returns {string[]} Array of short day names
323
- */
324
- getDayNames() {
325
- // If we have custom day names for this locale
326
- if (CUSTOM_DAY_NAMES[this.locale]) {
327
- const days = [...CUSTOM_DAY_NAMES[this.locale]];
328
- // Reorganize the days based on the first day of the week
329
- const firstDays = days.slice(0, this.firstDayOfWeek);
330
- const remainingDays = days.slice(this.firstDayOfWeek);
331
- return [...remainingDays, ...firstDays];
332
- }
333
- // Otherwise, use the default behavior
334
- const formatter = new Intl.DateTimeFormat(this.locale, {
335
- weekday: 'short',
336
- });
337
- const days = [...Array(7)].map((_, i) => formatter.format(new Date(2023, 0, i + 1)).toUpperCase());
338
- // Reorganize the days based on the first day of the week
339
- const firstDays = days.slice(0, this.firstDayOfWeek);
340
- const remainingDays = days.slice(this.firstDayOfWeek);
341
- return [...remainingDays, ...firstDays];
342
- }
343
- /**
344
- * Generates the days of the current month
345
- * @param {number} offset - Month offset (0 by default)
346
- * @param {number} totalCalendars - Number of calendars to display (1 by default)
347
- * @returns {Array<{ dayOfMonth: number | null, date: Date | null, isSelected: boolean, isDisabled: boolean }>} Array of formatted days
348
- */
349
- getDaysInMonth(offset = 0, totalCalendars = 1) {
350
- const year = this.currentDate.getUTCFullYear();
351
- const month = this.currentDate.getUTCMonth() + offset;
352
- const firstDay = new Date(Date.UTC(year, month, 1));
353
- const lastDay = new Date(Date.UTC(year, month + 1, 0));
354
- const days = [];
355
- // Correct calculation of offset for previous month days
356
- // Use getUTCDay to stay consistent with UTC timezone
357
- const dayOfWeekIndex = firstDay.getUTCDay(); // 0 = Sunday, 1 = Monday, etc.
358
- // Adjust based on firstDayOfWeek (if week starts on Monday, offset is different)
359
- const offsetDays = (dayOfWeekIndex - this.firstDayOfWeek + 7) % 7;
360
- // Add the days of the previous month for the first calendar
361
- if (offset === 0 && offsetDays > 0) {
362
- const prevMonthLastDay = new Date(Date.UTC(year, month, 0)).getUTCDate();
363
- for (let i = offsetDays; i > 0; i--) {
364
- const date = new Date(Date.UTC(year, month - 1, prevMonthLastDay - i + 1));
365
- days.push({
366
- dayOfMonth: date.getUTCDate(),
367
- date,
368
- isCurrentMonth: false,
369
- isDisabled: this.isDateDisabled(date),
560
+ //#endregion METHODS
561
+ /****************************************************************************/
562
+ //#region RENDER
563
+ /**
564
+ * Renders the header
565
+ * @param {number} offset - Month offset
566
+ * @param {number} index - Calendar index
567
+ * @returns {JSX.Element} Header
568
+ * @description Renders the header of the calendar
569
+ */
570
+ this.renderHeader = (offset, index) => {
571
+ return (h("div", { class: "header" }, this.numberOfCalendars > 1 && index === 0 && (h("nv-iconbutton", { class: "nav-left", emphasis: "lower", name: "chevron-left", onClick: this.getChangeMonthHandler(-1) })), h("div", { class: "date-controls" }, h("select", { class: "month-select mr-4", onChange: this.getHandleMonthChange(offset) }, this.months.map(month => (h("option", { key: month.value, value: month.value, selected: month.value === (this.currentDate.getUTCMonth() + offset) % 12 }, month.label)))), h("input", { type: "number", class: "year-input", min: "1950", max: "2100", value: this.currentDate.getUTCFullYear() +
572
+ Math.floor((this.currentDate.getUTCMonth() + offset) / 12), onChange: this.getHandleYearChange(offset) })), this.numberOfCalendars === 1 && (h("div", { class: "nav-buttons" }, h("nv-iconbutton", { emphasis: "lower", name: "chevron-left", onClick: this.getChangeMonthHandler(-1) }), h("nv-iconbutton", { emphasis: "lower", name: "chevron-right", onClick: this.getChangeMonthHandler(1) }))), this.numberOfCalendars > 1 && index === this.numberOfCalendars - 1 && (h("nv-iconbutton", { emphasis: "lower", name: "chevron-right", onClick: this.getChangeMonthHandler(1), class: "nav-right" }))));
573
+ };
574
+ /**
575
+ * Renders the week numbers
576
+ * @param {Array<{date: Date}>} weeks - Weeks to render
577
+ * @param {number} index - Calendar index
578
+ * @returns {JSX.Element} Week numbers
579
+ * @description Renders the week numbers of the calendar
580
+ */
581
+ this.renderWeekNumbers = (
582
+ /** Weeks to render */
583
+ weeks,
584
+ /** Calendar index */
585
+ index) => {
586
+ return (h("div", { class: "week-numbers" }, h("div", { class: "week-header" }, this.getLocalizedWeekText()), weeks.map((week, weekIndex) => {
587
+ var _a;
588
+ const dates = week.map(d => d.date);
589
+ return (h("div", { class: `week-number ${this.selectionType === 'range' ? 'clickable' : ''}`, onClick: this.getWeekSelectionHandler(dates, index), key: `week-${weekIndex}` }, getWeekNumber(((_a = week.find(d => d.date)) === null || _a === void 0 ? void 0 : _a.date) || new Date())));
590
+ })));
591
+ };
592
+ this.renderDaysGrid = (
593
+ /** Days to render */
594
+ days) => {
595
+ return (h("div", { class: "days-grid" }, days.map(day => {
596
+ const date = day.date;
597
+ if (!date)
598
+ return null;
599
+ const isSelected = this.selectionType === 'single' &&
600
+ isSameDate(date, this.selectedDate, { isUTCMode: this.isUTCMode });
601
+ const isInRange = this.isDateInRange(date);
602
+ const isStart = isSameDate(date, this.startDate, {
603
+ isUTCMode: this.isUTCMode,
370
604
  });
371
- }
372
- }
373
- // Add the days of the current month
374
- for (let i = 1; i <= lastDay.getUTCDate(); i++) {
375
- const date = new Date(Date.UTC(year, month, i));
376
- days.push({
377
- dayOfMonth: i,
378
- date,
379
- isCurrentMonth: true,
380
- isDisabled: this.isDateDisabled(date),
381
- });
382
- }
383
- // Add the days of the next month only for the last calendar
384
- if (offset === totalCalendars - 1) {
385
- const nextMonthDaysNeeded = 7 - (days.length % 7 || 7);
386
- for (let i = 1; i <= nextMonthDaysNeeded; i++) {
387
- const date = new Date(Date.UTC(year, month + 1, i));
388
- days.push({
389
- dayOfMonth: i,
390
- date,
391
- isCurrentMonth: false,
392
- isDisabled: this.isDateDisabled(date),
605
+ const isEnd = isSameDate(date, this.endDate, {
606
+ isUTCMode: this.isUTCMode,
393
607
  });
608
+ const isToday = this.isToday(date);
609
+ const isOutsideMonth = !day.isCurrentMonth;
610
+ const dayClasses = [
611
+ 'day',
612
+ isSelected ? 'selected' : '',
613
+ isStart ? 'range-start' : '',
614
+ isEnd ? 'range-end' : '',
615
+ isInRange ? 'in-range' : '',
616
+ day.isDisabled ? 'disabled' : '',
617
+ isOutsideMonth ? 'outside-month' : '',
618
+ isToday ? 'is-today' : '',
619
+ ];
620
+ return (h("div", { class: dayClasses.filter(Boolean).join(' '), onClick: this.getDayClickHandler(date, day.isDisabled), "aria-disabled": day.isDisabled, key: `day-${date.toISOString()}` }, day.dayOfMonth));
621
+ })));
622
+ };
623
+ /**
624
+ * Renders the calendar
625
+ * @param {number} index - Calendar index
626
+ * @param {number} offset - Month offset
627
+ * @returns {JSX.Element} Calendar
628
+ * @description Renders the calendar of the calendar
629
+ */
630
+ this.renderCalendar = (
631
+ /** Calendar index */
632
+ index,
633
+ /** Month offset */
634
+ offset) => {
635
+ const days = this.getDaysInMonth(offset, this.numberOfCalendars);
636
+ const weeks = [];
637
+ for (let i = 0; i < days.length; i += 7) {
638
+ weeks.push(days.slice(i, i + 7));
394
639
  }
395
- }
396
- return days;
397
- }
398
- /** Initializes the list of formatted months according to the locale */
399
- initializeMonths() {
400
- // If we have custom month names for this locale
401
- if (CUSTOM_MONTH_NAMES[this.locale]) {
402
- this.months = CUSTOM_MONTH_NAMES[this.locale].map((label, value) => ({
403
- value,
404
- label,
405
- }));
406
- return;
407
- }
408
- // Otherwise, use the default behavior
409
- const formatter = new Intl.DateTimeFormat(this.locale, { month: 'short' });
410
- this.months = Array.from({ length: 12 }, (_, i) => ({
411
- value: i,
412
- label: formatter.format(new Date(2000, i, 1)).toUpperCase(),
413
- }));
414
- }
415
- /**
416
- * Retrieves the localized abbreviation for "week"
417
- * @returns {string} Localized abbreviation for "week"
418
- */
419
- getLocalizedWeekText() {
420
- return WEEK_ABBREVIATIONS[this.locale] || 'W';
421
- }
422
- /**
423
- * Handles month change in the selector
424
- * @param {Event} event - Month change event
425
- * @param {number} calendarOffset - Calendar offset (0 by default)
426
- */
427
- handleMonthChange(event, calendarOffset = 0) {
428
- const select = event.target;
429
- const selectedMonth = parseInt(select.value, 10);
430
- const currentMonth = this.currentDate.getUTCMonth();
431
- // Calculate the difference considering the calendar offset
432
- const monthDiff = selectedMonth - ((currentMonth + calendarOffset) % 12);
433
- const newDate = new Date(this.currentDate);
434
- newDate.setUTCMonth(newDate.getUTCMonth() + monthDiff);
435
- this.currentDate = newDate;
436
- }
437
- /**
438
- * Handles year change in the numeric entry
439
- * @param {Event} event - Year change event
440
- * @param {number} calendarOffset - Calendar offset (0 by default)
441
- */
442
- handleYearChange(event, calendarOffset = 0) {
443
- const input = event.target;
444
- const year = parseInt(input.value, 10);
445
- if (!isNaN(year) && year >= 1900 && year <= 2100) {
446
- const newDate = new Date(this.currentDate);
447
- newDate.setUTCFullYear(year);
448
- newDate.setUTCMonth(newDate.getUTCMonth() + calendarOffset);
449
- this.currentDate = newDate;
450
- }
451
- }
452
- /**
453
- * Handles week selection
454
- * @param {Date[]} weekDays - Selected week days
455
- * @param {number} calendarIndex - Calendar index from which the selection is made
456
- */
457
- handleWeekSelection(weekDays, calendarIndex) {
458
- if (this.selectionType !== 'range')
459
- return;
460
- const allDays = this.getDaysInMonth(calendarIndex, this.numberOfCalendars);
461
- const weekStart = weekDays[0];
462
- const weekEnd = weekDays[weekDays.length - 1];
463
- if (!weekStart || !weekEnd)
464
- return;
465
- const selectedWeekDays = allDays.filter(day => day.date && day.date >= weekStart && day.date <= weekEnd);
466
- const validDays = selectedWeekDays.filter(day => !this.isDateDisabled(day.date));
467
- if (validDays.length > 0) {
468
- this.startDate = validDays[0].date;
469
- this.endDate = validDays[validDays.length - 1].date;
470
- this.rangeDateChange.emit({
471
- start: this.formatDate(this.startDate),
472
- end: this.formatDate(this.endDate),
473
- });
474
- }
475
- }
476
- /**
477
- * Checks if a date corresponds to today
478
- * @param {Date} date - Date to check
479
- * @returns {boolean} true if the date is today
480
- */
481
- isToday(date) {
482
- const today = new Date();
483
- return (date.getDate() === today.getDate() &&
484
- date.getMonth() === today.getMonth() &&
485
- date.getFullYear() === today.getFullYear());
640
+ return (h("div", { class: "calendar-wrapper" }, h("div", { class: "calendar-container", key: `calendar-${index}` }, this.renderHeader(offset, index), h("div", { class: "calendar-grid" }, this.showWeekNumbers && this.renderWeekNumbers(weeks, index), h("div", { class: "days-container" }, h("div", { class: "days-header" }, this.getDayNames().map(day => (h("div", { class: "day-header" }, day)))), this.renderDaysGrid(days)))), index < this.numberOfCalendars - 1 && (h("div", { class: "calendar-separator" }))));
641
+ };
642
+ /**
643
+ * Renders the shortcuts
644
+ * @returns {JSX.Element} Shortcuts
645
+ * @description Renders the shortcuts of the calendar
646
+ */
647
+ this.renderShortcuts = () => {
648
+ if (!this.hasShortcuts) {
649
+ return null;
650
+ }
651
+ return (h("div", { class: `shortcuts-container shortcuts-placement-${this.shortcutsPlacement}` }, this.shortcuts.map(shortcut => (h("nv-button", { emphasis: "lower", size: "xs", "aria-label": shortcut.label, onClick: this.getShortcutHandler(shortcut) }, shortcut.label)))));
652
+ };
653
+ /**
654
+ * Renders the actions
655
+ * @returns {JSX.Element} Actions
656
+ * @description Renders the actions of the calendar
657
+ * @slot actions - Child content of the component.
658
+ */
659
+ this.renderActions = () => {
660
+ return (h("div", { class: "datepicker-actions" }, h("slot", { name: "actions" }, h("nv-button", { emphasis: "low", size: "xs", onClick: this.resetSelection }, "Cancel"), h("nv-button", { size: "xs", onClick: this.confirmSelection }, "OK"))));
661
+ };
486
662
  }
663
+ //#endregion EVENTS
664
+ /****************************************************************************/
665
+ //#region WATCHERS
487
666
  /**
488
667
  * Watches the changes of the number of calendars
489
- * @watch numberOfCalendars
490
668
  * @param {number} newValue - New number of calendars
491
669
  */
492
670
  validateNumberOfCalendars(newValue) {
@@ -497,29 +675,25 @@ export class NvCalendar {
497
675
  }
498
676
  /**
499
677
  * Watches the changes of the selected date range
500
- * @watch rangeValue
501
678
  * @param {Object} newValue - New rangeValue value
502
679
  * @param {string} newValue.start - Start date
503
680
  * @param {string} newValue.end - End date
504
681
  */
505
682
  onRangeValueChange(newValue) {
506
- if (newValue) {
683
+ if (newValue && newValue.start && newValue.end) {
507
684
  try {
508
- const parsed = JSON.parse(newValue);
509
- if (parsed.start && parsed.end) {
510
- this.startDate = this.parseDate(parsed.start);
511
- this.endDate = this.parseDate(parsed.end);
512
- this.currentDate = this.parseDate(parsed.start);
513
- }
685
+ const { startDate, endDate } = this.validateDateRange(newValue.start, newValue.end);
686
+ this.startDate = startDate;
687
+ this.endDate = endDate;
688
+ this.currentDate = startDate;
514
689
  }
515
690
  catch (error) {
516
- console.error('Invalid JSON for rangeValue:', error);
691
+ console.error('Invalid rangeValue:', error);
517
692
  }
518
693
  }
519
694
  }
520
695
  /**
521
696
  * Watches the changes of the disabled dates
522
- * @watch disabledDates
523
697
  * @description Watches the changes of the disabled dates
524
698
  */
525
699
  handleDisabledDatesChange() {
@@ -527,381 +701,61 @@ export class NvCalendar {
527
701
  }
528
702
  /**
529
703
  * Watches the changes of the single value
530
- * @watch singleValue
531
704
  * @param {string} newValue - New single value
532
705
  * @param {string} oldValue - Old single value
533
706
  */
534
707
  onSingleValueChange(newValue, oldValue) {
535
708
  if (this.selectionType === 'single' && newValue !== oldValue && newValue) {
536
- const parsedDate = this.parseDate(newValue);
709
+ const parsedDate = parseDate(newValue, this.dateFormat);
537
710
  if (parsedDate) {
538
711
  this.selectedDate = parsedDate;
539
712
  this.currentDate = parsedDate;
540
713
  }
541
714
  }
542
715
  }
543
- /**
544
- * Convert a date string/Date to a Date without timezone offset
545
- * @param {string | Date} dateInput - Date under string or Date object form
546
- * @returns {Date} Date in Date form without timezone offset
547
- */
548
- parseDate(dateInput) {
549
- if (dateInput instanceof Date)
550
- return dateInput;
551
- // Attempt to automatically detect ISO 8601 format (generated by toISOString())
552
- // The regex checks the standard ISO format: YYYY-MM-DDTHH:mm:ss.sssZ
553
- if (typeof dateInput === 'string' &&
554
- /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/.test(dateInput)) {
716
+ //#endregion WATCHERS
717
+ /****************************************************************************/
718
+ //#region LIFECYCLE
719
+ componentWillLoad() {
720
+ this.parseDisabledDates();
721
+ if (this.selectionType === 'single' && this.singleValue) {
722
+ this.selectedDate = parseDate(this.singleValue, this.dateFormat);
723
+ this.currentDate = this.selectedDate;
724
+ }
725
+ else if (this.selectionType === 'range' && this.rangeValue) {
555
726
  try {
556
- const parsedDate = new Date(dateInput);
557
- if (!isNaN(parsedDate.getTime())) {
558
- return parsedDate;
727
+ if (this.rangeValue.start && this.rangeValue.end) {
728
+ const { startDate, endDate, swapped } = this.validateDateRange(this.rangeValue.start, this.rangeValue.end);
729
+ this.startDate = startDate;
730
+ this.endDate = endDate;
731
+ this.currentDate = startDate;
732
+ if (swapped) {
733
+ // If dates were swapped, update the rangeValue property
734
+ this.rangeValue = {
735
+ start: formatDate(startDate, { dateFormat: this.dateFormat }),
736
+ end: formatDate(endDate, { dateFormat: this.dateFormat }),
737
+ };
738
+ }
559
739
  }
560
740
  }
561
741
  catch (error) {
562
- // If it fails, continue with other methods
563
- console.error('Error parsing ISO date:', error);
564
- }
565
- }
566
- // Handling Unix Seconds ("X") formats
567
- if (this.dateFormat === 'X') {
568
- const unixSeconds = Number(dateInput);
569
- if (isNaN(unixSeconds))
570
- return null;
571
- return this.isUTCMode
572
- ? dayjs.unix(unixSeconds).utc().toDate()
573
- : dayjs.unix(unixSeconds).toDate();
574
- }
575
- // Handling Unix Milliseconds ("x") formats
576
- if (this.dateFormat === 'x') {
577
- const unixMilliseconds = Number(dateInput);
578
- if (isNaN(unixMilliseconds))
579
- return null;
580
- return this.isUTCMode
581
- ? dayjs(unixMilliseconds).utc().toDate()
582
- : dayjs(unixMilliseconds).toDate();
583
- }
584
- // Handling C# Ticks format
585
- if (this.dateFormat === 'Ticks') {
586
- const ticks = Number(dateInput);
587
- if (isNaN(ticks))
588
- return null;
589
- // Conversion of .NET ticks to milliseconds since Unix epoch
590
- const unixMilliseconds = (ticks - 621355968000000000) / 10000;
591
- return this.isUTCMode
592
- ? dayjs(unixMilliseconds).utc().toDate()
593
- : dayjs(unixMilliseconds).toDate();
594
- }
595
- // For all other formats, use customParseFormat in strict mode
596
- let parsed;
597
- if (this.isUTCMode) {
598
- parsed = dayjs.utc(dateInput, this.dateFormat, true);
599
- }
600
- else {
601
- parsed = dayjs(dateInput, this.dateFormat, true);
602
- }
603
- if (!parsed.isValid()) {
604
- console.error(`Parsing error:`, {
605
- dateInput,
606
- dateFormat: this.dateFormat,
607
- });
608
- return null;
609
- }
610
- return parsed.toDate();
611
- }
612
- /**
613
- * Checks if the date format is in UTC mode
614
- * @returns {boolean} true if the date format is in UTC mode
615
- */
616
- get isUTCMode() {
617
- return this.dateFormat.includes('Z');
618
- }
619
- /**
620
- * Checks if the date format is ISO 8601
621
- * @returns {boolean} true if the format is ISO 8601
622
- */
623
- get isISO8601Format() {
624
- return this.dateFormat === 'YYYY-MM-DD[T]HH:mm:ss[Z]';
625
- }
626
- /**
627
- * Formats a date to a string according to the format
628
- * @param {Date} date - Date to format
629
- * @returns {string} Formatted date
630
- */
631
- formatDate(date) {
632
- if (!date)
633
- return '';
634
- // Special case for ISO 8601
635
- if (this.isISO8601Format) {
636
- // For the ISO 8601 format, use directly toISOString() which is standard
637
- return date.toISOString();
638
- }
639
- // If the format is "Ticks", convert the time to C# ticks
640
- if (this.dateFormat === 'Ticks') {
641
- const ticks = date.getTime() * 10000 + 621355968000000000;
642
- return ticks.toString();
643
- }
644
- // If the format is "X" (Unix Seconds)
645
- if (this.dateFormat === 'X') {
646
- return dayjs(date).unix().toString();
647
- }
648
- // If the format is "x" (Unix Milliseconds)
649
- if (this.dateFormat === 'x') {
650
- return date.getTime().toString();
651
- }
652
- // Otherwise, format according to the mode (UTC or local)
653
- return this.isUTCMode
654
- ? dayjs(date).utc().format(this.dateFormat)
655
- : dayjs(date).format(this.dateFormat);
656
- }
657
- /**
658
- * Parse and cache the disabled dates
659
- * @description Parse and cache the disabled dates
660
- */
661
- parseDisabledDates() {
662
- if (!this.disabledDates) {
663
- this.parsedDisabledDates = [];
664
- return;
665
- }
666
- try {
667
- const disabledDatesArray = JSON.parse(this.disabledDates);
668
- this.parsedDisabledDates = disabledDatesArray
669
- .map(date => this.parseDate(date))
670
- .filter(date => date !== null);
671
- }
672
- catch (error) {
673
- console.error('Error parsing disabled dates:', error);
674
- this.parsedDisabledDates = [];
675
- }
676
- }
677
- /**
678
- * Checks if two dates are identical
679
- * @param {Date | null} date1 - First date
680
- * @param {Date | null} date2 - Second date
681
- * @returns {boolean} true if the dates are identical
682
- */
683
- isSameDate(date1, date2) {
684
- if (!date1 || !date2)
685
- return false;
686
- if (this.isUTCMode) {
687
- return (date1.getUTCFullYear() === date2.getUTCFullYear() &&
688
- date1.getUTCMonth() === date2.getUTCMonth() &&
689
- date1.getUTCDate() === date2.getUTCDate());
690
- }
691
- else {
692
- return (date1.getFullYear() === date2.getFullYear() &&
693
- date1.getMonth() === date2.getMonth() &&
694
- date1.getDate() === date2.getDate());
695
- }
696
- }
697
- /**
698
- * Checks if a date is identical or after another date
699
- * @param {Date} date - Date to check
700
- * @param {Date} compareDate - Reference date
701
- * @returns {boolean} true if `date` >= `compareDate`
702
- */
703
- isSameOrAfter(date, compareDate) {
704
- if (this.isUTCMode) {
705
- return (date.getUTCFullYear() > compareDate.getUTCFullYear() ||
706
- (date.getUTCFullYear() === compareDate.getUTCFullYear() &&
707
- date.getUTCMonth() > compareDate.getUTCMonth()) ||
708
- (date.getUTCFullYear() === compareDate.getUTCFullYear() &&
709
- date.getUTCMonth() === compareDate.getUTCMonth() &&
710
- date.getUTCDate() >= compareDate.getUTCDate()));
711
- }
712
- else {
713
- return (date.getFullYear() > compareDate.getFullYear() ||
714
- (date.getFullYear() === compareDate.getFullYear() &&
715
- date.getMonth() > compareDate.getMonth()) ||
716
- (date.getFullYear() === compareDate.getFullYear() &&
717
- date.getMonth() === compareDate.getMonth() &&
718
- date.getDate() >= compareDate.getDate()));
719
- }
720
- }
721
- /**
722
- * Checks if a date is identical or before another date
723
- * @param {Date} date - Date to check
724
- * @param {Date} compareDate - Reference date
725
- * @returns {boolean} true if `date` <= `compareDate`
726
- */
727
- isSameOrBefore(date, compareDate) {
728
- if (this.isUTCMode) {
729
- return (date.getUTCFullYear() < compareDate.getUTCFullYear() ||
730
- (date.getUTCFullYear() === compareDate.getUTCFullYear() &&
731
- date.getUTCMonth() < compareDate.getUTCMonth()) ||
732
- (date.getUTCFullYear() === compareDate.getUTCFullYear() &&
733
- date.getUTCMonth() === compareDate.getUTCMonth() &&
734
- date.getUTCDate() <= compareDate.getUTCDate()));
735
- }
736
- else {
737
- return (date.getFullYear() < compareDate.getFullYear() ||
738
- (date.getFullYear() === compareDate.getFullYear() &&
739
- date.getMonth() < compareDate.getMonth()) ||
740
- (date.getFullYear() === compareDate.getFullYear() &&
741
- date.getMonth() === compareDate.getMonth() &&
742
- date.getDate() <= compareDate.getDate()));
743
- }
744
- }
745
- /**
746
- * Applies a shortcut selection
747
- * @param {Object} shortcut - Shortcut to apply
748
- * @param {string | Date} shortcut.singleValue - Selected date value
749
- * @param {Object} shortcut.rangeValue - Start and end date values
750
- * @param {string | Date} shortcut.rangeValue.start - Start date value
751
- * @param {string | Date} shortcut.rangeValue.end - End date value
752
- * @param {string} shortcut.label - Label
753
- */
754
- applyShortcut(shortcut) {
755
- this.selectedDate = null;
756
- this.startDate = null;
757
- this.endDate = null;
758
- if (shortcut.singleValue) {
759
- const newDate = this.parseDate(shortcut.singleValue);
760
- this.selectedDate = newDate;
761
- this.singleDateChange.emit(this.formatDate(newDate));
762
- this.singleValue = this.formatDate(newDate);
763
- if (!this.showActions) {
764
- const event = new CustomEvent('closePopover', {
765
- bubbles: true,
766
- composed: true,
767
- });
768
- this.el.dispatchEvent(event);
742
+ console.error('Invalid rangeValue:', error);
769
743
  }
770
- this.forceCalendarUpdate(newDate);
771
744
  }
772
745
  else {
773
- const start = this.parseDate(shortcut.rangeValue.start);
774
- const end = this.parseDate(shortcut.rangeValue.end);
775
- this.startDate = start;
776
- this.endDate = end;
777
- this.rangeDateChange.emit({
778
- start: this.formatDate(start),
779
- end: this.formatDate(end),
780
- });
781
- this.rangeValue = JSON.stringify({
782
- start: this.formatDate(start),
783
- end: this.formatDate(end),
784
- });
785
- if (!this.showActions) {
786
- const event = new CustomEvent('closePopover', {
787
- bubbles: true,
788
- composed: true,
789
- });
790
- this.el.dispatchEvent(event);
791
- }
792
- this.forceCalendarUpdate(end);
793
- }
794
- }
795
- /**
796
- * Method to force the complete calendar update (and fix the persistent hover problem)
797
- * @param {Date} newDate - Date to force
798
- */
799
- forceCalendarUpdate(newDate) {
800
- this.currentDate = new Date(newDate);
801
- this.currentDate = new Date(this.currentDate); // Force a re-render
802
- // Reset visually the hover/touch effect
803
- requestAnimationFrame(() => {
804
- const days = document.querySelectorAll('.day');
805
- days.forEach(el => {
806
- el.classList.remove('hover', 'active', 'touched');
807
- el.style.pointerEvents = 'none';
808
- });
809
- // Add specific touch handling (for mobile)
810
- document.body.addEventListener('touchstart', this.clearTouchState, {
811
- passive: true,
812
- });
813
- // Reset the touch state after 50ms
814
- setTimeout(() => {
815
- days.forEach(el => {
816
- el.style.pointerEvents = '';
817
- });
818
- }, 50);
819
- });
820
- }
821
- /**
822
- * Function to reset the touch effect (Mobile fix)
823
- */
824
- clearTouchState() {
825
- document.querySelectorAll('.day').forEach(el => {
826
- el.classList.remove('touched');
827
- });
828
- // Remove the listener after the first interaction
829
- document.body.removeEventListener('touchstart', this.clearTouchState);
830
- }
831
- /**
832
- * Handles month change with an offset
833
- * @param {number} direction - Direction (-1 for previous, 1 for next)
834
- * @returns {Function} Change month handler
835
- */
836
- getChangeMonthHandler(direction) {
837
- return () => this.changeMonth(direction);
838
- }
839
- /**
840
- * Handles month change from an event (ex: dropdown)
841
- * @param {number} offset - Month offset (0 by default)
842
- * @returns {Function} Change month handler
843
- */
844
- getHandleMonthChange(offset) {
845
- return (event) => this.handleMonthChange(event, offset);
846
- }
847
- /**
848
- * Handles year change from an event (ex: dropdown)
849
- * @param {number} offset - Year offset (0 by default)
850
- * @returns {Function} Change year handler
851
- */
852
- getHandleYearChange(offset) {
853
- return (event) => this.handleYearChange(event, offset);
854
- }
855
- /**
856
- * Handles day click
857
- * @param {Date} date - Date to handle
858
- * @param {boolean} isDisabled - Whether the date is disabled
859
- * @returns {Function} Day click handler
860
- */
861
- getDayClickHandler(date, isDisabled) {
862
- return isDisabled ? undefined : () => this.handleDateSelection(date);
863
- }
864
- /**
865
- * Handles shortcut selection
866
- * @param {Object} shortcut - Shortcut to handle
867
- * @param {string | Date} shortcut.singleValue - Selected date value
868
- * @param {Object} shortcut.rangeValue - Start and end date values
869
- * @param {string | Date} shortcut.rangeValue.start - Start date value
870
- * @param {string | Date} shortcut.rangeValue.end - End date value
871
- * @param {string} shortcut.label - Label
872
- * @returns {Function} Shortcut selection handler
873
- */
874
- getShortcutHandler(shortcut) {
875
- return () => this.applyShortcut(shortcut);
876
- }
877
- /**
878
- * Handles week selection
879
- * @param {Date[]} dates - Dates to handle
880
- * @param {number} index - Calendar index
881
- * @returns {Function} Week selection handler
882
- */
883
- getWeekSelectionHandler(dates, index) {
884
- return () => {
885
- if (this.selectionType === 'range') {
886
- this.handleWeekSelection(dates, index);
887
- }
888
- };
889
- }
890
- parsedShortcuts() {
891
- try {
892
- return this.shortcuts ? JSON.parse(this.shortcuts) : [];
893
- }
894
- catch (error) {
895
- console.error('Invalid JSON for shortcuts:', error);
896
- return [];
746
+ this.currentDate = new Date();
897
747
  }
748
+ this.initializeMonths();
898
749
  }
750
+ //#endregion LIFECYCLE
751
+ /****************************************************************************/
752
+ //#region METHODS
899
753
  /**
900
754
  * Checks if shortcuts are visible
901
755
  * @returns {boolean} true if shortcuts are visible
902
756
  */
903
757
  get hasShortcuts() {
904
- return (this.shortcutsPlacement === 'bottom' && this.parsedShortcuts().length > 0);
758
+ return Boolean(this.shortcutsPlacement && this.shortcuts);
905
759
  }
906
760
  /**
907
761
  * Checks if actions are visible
@@ -910,103 +764,46 @@ export class NvCalendar {
910
764
  get hasActions() {
911
765
  return this.showActions;
912
766
  }
913
- //#endregion METHODS
914
- /****************************************************************************/
915
- //#region RENDER
916
767
  /**
917
- * Renders the header
918
- * @param {number} offset - Month offset
919
- * @param {number} index - Calendar index
920
- * @returns {JSX.Element} Header
921
- * @description Renders the header of the calendar
922
- */
923
- renderHeader(offset, index) {
924
- return (h("div", { class: "header" }, this.numberOfCalendars > 1 && index === 0 && (h("nv-iconbutton", { class: "nav-left", emphasis: "lower", name: "chevron-left", onClick: this.getChangeMonthHandler(-1) })), h("div", { class: "date-controls" }, h("select", { class: "month-select mr-4", onChange: this.getHandleMonthChange(offset) }, this.months.map(month => (h("option", { key: month.value, value: month.value, selected: month.value === (this.currentDate.getUTCMonth() + offset) % 12 }, month.label)))), h("input", { type: "number", class: "year-input", min: "1950", max: "2100", value: this.currentDate.getUTCFullYear() +
925
- Math.floor((this.currentDate.getUTCMonth() + offset) / 12), onChange: this.getHandleYearChange(offset) })), this.numberOfCalendars === 1 && (h("div", { class: "nav-buttons" }, h("nv-iconbutton", { emphasis: "lower", name: "chevron-left", onClick: this.getChangeMonthHandler(-1) }), h("nv-iconbutton", { emphasis: "lower", name: "chevron-right", onClick: this.getChangeMonthHandler(1) }))), this.numberOfCalendars > 1 && index === this.numberOfCalendars - 1 && (h("nv-iconbutton", { emphasis: "lower", name: "chevron-right", onClick: this.getChangeMonthHandler(1), class: "nav-right" }))));
926
- }
927
- /**
928
- * Renders the week numbers
929
- * @param {Array<{date: Date}>} weeks - Weeks to render
930
- * @param {number} index - Calendar index
931
- * @returns {JSX.Element} Week numbers
932
- * @description Renders the week numbers of the calendar
768
+ * Checks if the date format is in UTC mode
769
+ * @returns {boolean} true if the date format is in UTC mode
933
770
  */
934
- renderWeekNumbers(
935
- /** Weeks to render */
936
- weeks,
937
- /** Calendar index */
938
- index) {
939
- return (h("div", { class: "week-numbers" }, h("div", { class: "week-header" }, this.getLocalizedWeekText()), weeks.map((week, weekIndex) => {
940
- var _a;
941
- const dates = week.map(d => d.date);
942
- return (h("div", { class: `week-number ${this.selectionType === 'range' ? 'clickable' : ''}`, onClick: this.getWeekSelectionHandler(dates, index), key: `week-${weekIndex}` }, this.getWeekNumber(((_a = week.find(d => d.date)) === null || _a === void 0 ? void 0 : _a.date) || new Date())));
943
- })));
944
- }
945
- renderDaysGrid(
946
- /** Days to render */
947
- days) {
948
- return (h("div", { class: "days-grid" }, days.map(day => {
949
- const date = day.date;
950
- if (!date)
951
- return null;
952
- const isSelected = this.selectionType === 'single' &&
953
- this.isSameDate(date, this.selectedDate);
954
- const isInRange = this.isDateInRange(date);
955
- const isStart = this.isSameDate(date, this.startDate);
956
- const isEnd = this.isSameDate(date, this.endDate);
957
- const isToday = this.isToday(date);
958
- const isOutsideMonth = !day.isCurrentMonth;
959
- const dayClasses = [
960
- 'day',
961
- isSelected ? 'selected' : '',
962
- isStart ? 'range-start' : '',
963
- isEnd ? 'range-end' : '',
964
- isInRange ? 'in-range' : '',
965
- day.isDisabled ? 'disabled' : '',
966
- isOutsideMonth ? 'outside-month' : '',
967
- isToday ? 'is-today' : '',
968
- ];
969
- return (h("div", { class: dayClasses.filter(Boolean).join(' '), onClick: this.getDayClickHandler(date, day.isDisabled), "aria-disabled": day.isDisabled, key: `day-${date.toISOString()}` }, day.dayOfMonth));
970
- })));
771
+ get isUTCMode() {
772
+ return this.dateFormat.includes('Z');
971
773
  }
972
774
  /**
973
- * Renders the calendar
974
- * @param {number} index - Calendar index
975
- * @param {number} offset - Month offset
976
- * @returns {JSX.Element} Calendar
977
- * @description Renders the calendar of the calendar
775
+ * Validates and processes a date range, warning if start is after end
776
+ * @param {string} startDateStr - Start date in ISO string format
777
+ * @param {string} endDateStr - End date in ISO string format
778
+ * @returns {object} Object containing the validated start and end dates
978
779
  */
979
- renderCalendar(
980
- /** Calendar index */
981
- index,
982
- /** Month offset */
983
- offset) {
984
- const days = this.getDaysInMonth(offset, this.numberOfCalendars);
985
- const weeks = [];
986
- for (let i = 0; i < days.length; i += 7) {
987
- weeks.push(days.slice(i, i + 7));
780
+ validateDateRange(startDateStr, endDateStr) {
781
+ try {
782
+ const startDate = parseDate(startDateStr, this.dateFormat);
783
+ const endDate = parseDate(endDateStr, this.dateFormat);
784
+ if (startDate && endDate && startDate > endDate) {
785
+ console.warn(`Warning: startDate (${formatDate(startDate, {
786
+ dateFormat: this.dateFormat,
787
+ })}) is after endDate (${formatDate(endDate, {
788
+ dateFormat: this.dateFormat,
789
+ })})`);
790
+ // Return dates in correct order, with swapped flag
791
+ return {
792
+ startDate: endDate,
793
+ endDate: startDate,
794
+ swapped: true,
795
+ };
796
+ }
797
+ return {
798
+ startDate,
799
+ endDate,
800
+ swapped: false,
801
+ };
988
802
  }
989
- return (h("div", { class: "calendar-wrapper" }, h("div", { class: "calendar-container", key: `calendar-${index}` }, this.renderHeader(offset, index), h("div", { class: "calendar-grid" }, this.showWeekNumbers && this.renderWeekNumbers(weeks, index), h("div", { class: "days-container" }, h("div", { class: "days-header" }, this.getDayNames().map(day => (h("div", { class: "day-header" }, day)))), this.renderDaysGrid(days)))), index < this.numberOfCalendars - 1 && (h("div", { class: "calendar-separator" }))));
990
- }
991
- /**
992
- * Renders the shortcuts
993
- * @returns {JSX.Element} Shortcuts
994
- * @description Renders the shortcuts of the calendar
995
- */
996
- renderShortcuts() {
997
- if (!this.parsedShortcuts().length) {
998
- return null;
803
+ catch (error) {
804
+ console.error('Invalid date range:', error);
805
+ throw error; // Re-throw to let the caller handle it
999
806
  }
1000
- return (h("div", { class: `shortcuts-container shortcuts-placement-${this.shortcutsPlacement}` }, this.parsedShortcuts().map(shortcut => (h("nv-button", { emphasis: "lower", size: "xs", "aria-label": shortcut.label, onClick: this.getShortcutHandler(shortcut) }, shortcut.label)))));
1001
- }
1002
- /**
1003
- * Renders the actions
1004
- * @returns {JSX.Element} Actions
1005
- * @description Renders the actions of the calendar
1006
- * @slot actions - Child content of the component.
1007
- */
1008
- renderActions() {
1009
- return (h("div", { class: "datepicker-actions" }, h("slot", { name: "actions" }, h("nv-button", { emphasis: "low", size: "xs", onClick: this.resetSelection }, "Cancel"), h("nv-button", { size: "xs", onClick: this.confirmSelection }, "OK"))));
1010
807
  }
1011
808
  /**
1012
809
  * Renders the datepicker
@@ -1015,7 +812,8 @@ export class NvCalendar {
1015
812
  * @slot default - Child content of the component.
1016
813
  */
1017
814
  render() {
1018
- return (h(Host, { key: '89300da9f694aa926855452414e7e036f75f2de6' }, h("div", { key: '467ef9fc9d6523eec3712bf779d49fdf50c55617', class: "datepicker-root" }, h("div", { key: '990f2cb18dcad96cab0f8dfb62e6c57049475440', class: `datepicker-container ${this.numberOfCalendars === 1 ? 'datepicker-container-single' : ''}` }, h("div", { key: 'c0dedf1007cbc6a87bd591925c9994474c876afc', class: `datepicker-wrapper ${this.numberOfCalendars === 1 ? 'single' : ''}` }, this.shortcutsPlacement === 'left' && this.renderShortcuts(), Array.from({ length: this.numberOfCalendars }, (_, index) => this.renderCalendar(index, index)), this.shortcutsPlacement === 'right' && this.renderShortcuts()), (this.hasShortcuts || this.hasActions) && (h("div", { key: 'ef81eaf952fbe569be7e1d3ee6cb59de0e137fe4', class: "datepicker-controls" }, this.hasShortcuts && this.renderShortcuts(), this.hasActions && this.renderActions())))), h("slot", { key: 'e1281217950b5cb02952a69b081d4fcce5863b4d' })));
815
+ return (h(Host, { key: 'd265f105851253b5aa2a40e055f8e51b5cb6b553' }, h("div", { key: 'c6e1ea923b17f7684243598109e4cffc767248d7', class: "datepicker-root" }, h("div", { key: '5fc4cfbf3f6d823c500408d0f81f5f15d3e654d7', class: `datepicker-container ${this.numberOfCalendars === 1 ? 'datepicker-container-single' : ''}` }, h("div", { key: '035dac25c8b8090e1a3a0ac2493865907f665da9', class: `datepicker-wrapper ${this.numberOfCalendars === 1 ? 'single' : ''}` }, this.shortcutsPlacement === 'left' && this.renderShortcuts(), Array.from({ length: this.numberOfCalendars }, (_, index) => this.renderCalendar(index, index)), this.shortcutsPlacement === 'right' && this.renderShortcuts()), ((this.hasShortcuts && this.shortcutsPlacement === 'bottom') ||
816
+ this.hasActions) && (h("div", { key: '91c21c945ab53acda631a8c50fb1437665fce030', class: "datepicker-controls" }, this.shortcutsPlacement === 'bottom' && this.renderShortcuts(), this.hasActions && this.renderActions())))), h("slot", { key: '3799c412c842e406715c235d3288022c2a734ed2' })));
1019
817
  }
1020
818
  static get is() { return "nv-calendar"; }
1021
819
  static get originalStyleUrls() {
@@ -1093,15 +891,14 @@ export class NvCalendar {
1093
891
  "getter": false,
1094
892
  "setter": false,
1095
893
  "attribute": "single-value",
1096
- "reflect": true,
1097
- "defaultValue": "''"
894
+ "reflect": true
1098
895
  },
1099
896
  "rangeValue": {
1100
- "type": "string",
897
+ "type": "unknown",
1101
898
  "mutable": true,
1102
899
  "complexType": {
1103
- "original": "string",
1104
- "resolved": "string",
900
+ "original": "{\n /** ISO string for start date */\n start: string;\n /** ISO string for end date */\n end: string;\n }",
901
+ "resolved": "{ start: string; end: string; }",
1105
902
  "references": {}
1106
903
  },
1107
904
  "required": false,
@@ -1111,10 +908,7 @@ export class NvCalendar {
1111
908
  "text": "Selected date range\nformat: { start: ISO string, end: ISO string }\nex: { start: \"2025-03-15\", end: \"2025-03-20\" }"
1112
909
  },
1113
910
  "getter": false,
1114
- "setter": false,
1115
- "attribute": "range-value",
1116
- "reflect": true,
1117
- "defaultValue": "''"
911
+ "setter": false
1118
912
  },
1119
913
  "min": {
1120
914
  "type": "string",
@@ -1133,8 +927,7 @@ export class NvCalendar {
1133
927
  "getter": false,
1134
928
  "setter": false,
1135
929
  "attribute": "min",
1136
- "reflect": true,
1137
- "defaultValue": "''"
930
+ "reflect": true
1138
931
  },
1139
932
  "max": {
1140
933
  "type": "string",
@@ -1153,31 +946,29 @@ export class NvCalendar {
1153
946
  "getter": false,
1154
947
  "setter": false,
1155
948
  "attribute": "max",
1156
- "reflect": true,
1157
- "defaultValue": "''"
949
+ "reflect": true
1158
950
  },
1159
951
  "disabledDates": {
1160
- "type": "string",
952
+ "type": "unknown",
1161
953
  "mutable": false,
1162
954
  "complexType": {
1163
- "original": "string",
1164
- "resolved": "string",
1165
- "references": {}
955
+ "original": "Array<string>",
956
+ "resolved": "string[]",
957
+ "references": {
958
+ "Array": {
959
+ "location": "global",
960
+ "id": "global::Array"
961
+ }
962
+ }
1166
963
  },
1167
964
  "required": false,
1168
965
  "optional": false,
1169
966
  "docs": {
1170
- "tags": [{
1171
- "name": "default",
1172
- "text": "'[]'"
1173
- }],
967
+ "tags": [],
1174
968
  "text": "Disabled dates (ISO string array)"
1175
969
  },
1176
970
  "getter": false,
1177
- "setter": false,
1178
- "attribute": "disabled-dates",
1179
- "reflect": true,
1180
- "defaultValue": "''"
971
+ "setter": false
1181
972
  },
1182
973
  "locale": {
1183
974
  "type": "string",
@@ -1288,10 +1079,7 @@ export class NvCalendar {
1288
1079
  "required": false,
1289
1080
  "optional": false,
1290
1081
  "docs": {
1291
- "tags": [{
1292
- "name": "default",
1293
- "text": "false"
1294
- }],
1082
+ "tags": [],
1295
1083
  "text": "Show action buttons"
1296
1084
  },
1297
1085
  "getter": false,
@@ -1301,27 +1089,26 @@ export class NvCalendar {
1301
1089
  "defaultValue": "false"
1302
1090
  },
1303
1091
  "shortcuts": {
1304
- "type": "string",
1092
+ "type": "unknown",
1305
1093
  "mutable": false,
1306
1094
  "complexType": {
1307
- "original": "string",
1308
- "resolved": "string",
1309
- "references": {}
1095
+ "original": "{\n /** Label of the shortcut */\n label: string;\n /** Selected date value for single selection mode */\n singleValue?: string;\n /** Date range values for range selection mode */\n rangeValue?: HTMLNvCalendarElement['rangeValue'];\n }[]",
1096
+ "resolved": "{ label: string; singleValue?: string; rangeValue?: { start: string; end: string; }; }[]",
1097
+ "references": {
1098
+ "HTMLNvCalendarElement": {
1099
+ "location": "global",
1100
+ "id": "global::HTMLNvCalendarElement"
1101
+ }
1102
+ }
1310
1103
  },
1311
1104
  "required": false,
1312
1105
  "optional": false,
1313
1106
  "docs": {
1314
- "tags": [{
1315
- "name": "default",
1316
- "text": "'[]'"
1317
- }],
1318
- "text": "Custom actions to display in the footer\nJSON array of objects with the following properties:\n- label: string\n- onClick: function"
1107
+ "tags": [],
1108
+ "text": "Custom actions to display in the footer"
1319
1109
  },
1320
1110
  "getter": false,
1321
- "setter": false,
1322
- "attribute": "shortcuts",
1323
- "reflect": true,
1324
- "defaultValue": "'[]'"
1111
+ "setter": false
1325
1112
  },
1326
1113
  "showWeekNumbers": {
1327
1114
  "type": "boolean",
@@ -1334,10 +1121,7 @@ export class NvCalendar {
1334
1121
  "required": false,
1335
1122
  "optional": false,
1336
1123
  "docs": {
1337
- "tags": [{
1338
- "name": "default",
1339
- "text": "true"
1340
- }],
1124
+ "tags": [],
1341
1125
  "text": "Show week numbers"
1342
1126
  },
1343
1127
  "getter": false,
@@ -1383,13 +1167,12 @@ export class NvCalendar {
1383
1167
  "text": "Emitted when a date range is selected"
1384
1168
  },
1385
1169
  "complexType": {
1386
- "original": "DateRange",
1387
- "resolved": "DateRange",
1170
+ "original": "HTMLNvCalendarElement['rangeValue']",
1171
+ "resolved": "{ start: string; end: string; }",
1388
1172
  "references": {
1389
- "DateRange": {
1390
- "location": "import",
1391
- "path": "../../interfaces/dateRange",
1392
- "id": "src/interfaces/dateRange.tsx::DateRange"
1173
+ "HTMLNvCalendarElement": {
1174
+ "location": "global",
1175
+ "id": "global::HTMLNvCalendarElement"
1393
1176
  }
1394
1177
  }
1395
1178
  }