@keenthemes/ktui 1.0.3

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 (426) hide show
  1. package/CONTRIBUTING.md +88 -0
  2. package/LICENSE.md +21 -0
  3. package/README.md +124 -0
  4. package/dist/ktui.js +19201 -0
  5. package/dist/ktui.min.js +2 -0
  6. package/dist/ktui.min.js.map +1 -0
  7. package/lib/cjs/components/accordion/accordion.js +168 -0
  8. package/lib/cjs/components/accordion/accordion.js.map +1 -0
  9. package/lib/cjs/components/accordion/index.js +6 -0
  10. package/lib/cjs/components/accordion/index.js.map +1 -0
  11. package/lib/cjs/components/accordion/types.js +3 -0
  12. package/lib/cjs/components/accordion/types.js.map +1 -0
  13. package/lib/cjs/components/collapse/collapse.js +169 -0
  14. package/lib/cjs/components/collapse/collapse.js.map +1 -0
  15. package/lib/cjs/components/collapse/index.js +6 -0
  16. package/lib/cjs/components/collapse/index.js.map +1 -0
  17. package/lib/cjs/components/collapse/types.js +3 -0
  18. package/lib/cjs/components/collapse/types.js.map +1 -0
  19. package/lib/cjs/components/component.js +135 -0
  20. package/lib/cjs/components/component.js.map +1 -0
  21. package/lib/cjs/components/config.js +26 -0
  22. package/lib/cjs/components/config.js.map +1 -0
  23. package/lib/cjs/components/config.umd.js +23 -0
  24. package/lib/cjs/components/config.umd.js.map +1 -0
  25. package/lib/cjs/components/constants.js +15 -0
  26. package/lib/cjs/components/constants.js.map +1 -0
  27. package/lib/cjs/components/datatable/datatable.js +1464 -0
  28. package/lib/cjs/components/datatable/datatable.js.map +1 -0
  29. package/lib/cjs/components/datatable/index.js +6 -0
  30. package/lib/cjs/components/datatable/index.js.map +1 -0
  31. package/lib/cjs/components/datatable/types.js +3 -0
  32. package/lib/cjs/components/datatable/types.js.map +1 -0
  33. package/lib/cjs/components/dismiss/dismiss.js +131 -0
  34. package/lib/cjs/components/dismiss/dismiss.js.map +1 -0
  35. package/lib/cjs/components/dismiss/index.js +6 -0
  36. package/lib/cjs/components/dismiss/index.js.map +1 -0
  37. package/lib/cjs/components/dismiss/types.js +3 -0
  38. package/lib/cjs/components/dismiss/types.js.map +1 -0
  39. package/lib/cjs/components/drawer/drawer.js +347 -0
  40. package/lib/cjs/components/drawer/drawer.js.map +1 -0
  41. package/lib/cjs/components/drawer/index.js +6 -0
  42. package/lib/cjs/components/drawer/index.js.map +1 -0
  43. package/lib/cjs/components/drawer/types.js +3 -0
  44. package/lib/cjs/components/drawer/types.js.map +1 -0
  45. package/lib/cjs/components/dropdown/dropdown.js +403 -0
  46. package/lib/cjs/components/dropdown/dropdown.js.map +1 -0
  47. package/lib/cjs/components/dropdown/index.js +6 -0
  48. package/lib/cjs/components/dropdown/index.js.map +1 -0
  49. package/lib/cjs/components/dropdown/types.js +3 -0
  50. package/lib/cjs/components/dropdown/types.js.map +1 -0
  51. package/lib/cjs/components/image-input/image-input.js +191 -0
  52. package/lib/cjs/components/image-input/image-input.js.map +1 -0
  53. package/lib/cjs/components/image-input/index.js +6 -0
  54. package/lib/cjs/components/image-input/index.js.map +1 -0
  55. package/lib/cjs/components/image-input/types.js +3 -0
  56. package/lib/cjs/components/image-input/types.js.map +1 -0
  57. package/lib/cjs/components/menu/index.js +6 -0
  58. package/lib/cjs/components/menu/index.js.map +1 -0
  59. package/lib/cjs/components/menu/menu.js +1021 -0
  60. package/lib/cjs/components/menu/menu.js.map +1 -0
  61. package/lib/cjs/components/menu/types.js +3 -0
  62. package/lib/cjs/components/menu/types.js.map +1 -0
  63. package/lib/cjs/components/modal/index.js +6 -0
  64. package/lib/cjs/components/modal/index.js.map +1 -0
  65. package/lib/cjs/components/modal/modal.js +316 -0
  66. package/lib/cjs/components/modal/modal.js.map +1 -0
  67. package/lib/cjs/components/modal/types.js +3 -0
  68. package/lib/cjs/components/modal/types.js.map +1 -0
  69. package/lib/cjs/components/reparent/index.js +6 -0
  70. package/lib/cjs/components/reparent/index.js.map +1 -0
  71. package/lib/cjs/components/reparent/reparent.js +93 -0
  72. package/lib/cjs/components/reparent/reparent.js.map +1 -0
  73. package/lib/cjs/components/reparent/types.js +3 -0
  74. package/lib/cjs/components/reparent/types.js.map +1 -0
  75. package/lib/cjs/components/scrollable/index.js +6 -0
  76. package/lib/cjs/components/scrollable/index.js.map +1 -0
  77. package/lib/cjs/components/scrollable/scrollable.js +259 -0
  78. package/lib/cjs/components/scrollable/scrollable.js.map +1 -0
  79. package/lib/cjs/components/scrollable/types.js +3 -0
  80. package/lib/cjs/components/scrollable/types.js.map +1 -0
  81. package/lib/cjs/components/scrollspy/index.js +6 -0
  82. package/lib/cjs/components/scrollspy/index.js.map +1 -0
  83. package/lib/cjs/components/scrollspy/scrollspy.js +174 -0
  84. package/lib/cjs/components/scrollspy/scrollspy.js.map +1 -0
  85. package/lib/cjs/components/scrollspy/types.js +3 -0
  86. package/lib/cjs/components/scrollspy/types.js.map +1 -0
  87. package/lib/cjs/components/scrollto/index.js +6 -0
  88. package/lib/cjs/components/scrollto/index.js.map +1 -0
  89. package/lib/cjs/components/scrollto/scrollto.js +103 -0
  90. package/lib/cjs/components/scrollto/scrollto.js.map +1 -0
  91. package/lib/cjs/components/scrollto/types.js +3 -0
  92. package/lib/cjs/components/scrollto/types.js.map +1 -0
  93. package/lib/cjs/components/stepper/index.js +6 -0
  94. package/lib/cjs/components/stepper/index.js.map +1 -0
  95. package/lib/cjs/components/stepper/stepper.js +258 -0
  96. package/lib/cjs/components/stepper/stepper.js.map +1 -0
  97. package/lib/cjs/components/stepper/types.js +3 -0
  98. package/lib/cjs/components/stepper/types.js.map +1 -0
  99. package/lib/cjs/components/sticky/index.js +6 -0
  100. package/lib/cjs/components/sticky/index.js.map +1 -0
  101. package/lib/cjs/components/sticky/sticky.js +297 -0
  102. package/lib/cjs/components/sticky/sticky.js.map +1 -0
  103. package/lib/cjs/components/sticky/types.js +3 -0
  104. package/lib/cjs/components/sticky/types.js.map +1 -0
  105. package/lib/cjs/components/tabs/index.js +6 -0
  106. package/lib/cjs/components/tabs/index.js.map +1 -0
  107. package/lib/cjs/components/tabs/tabs.js +146 -0
  108. package/lib/cjs/components/tabs/tabs.js.map +1 -0
  109. package/lib/cjs/components/tabs/types.js +3 -0
  110. package/lib/cjs/components/tabs/types.js.map +1 -0
  111. package/lib/cjs/components/theme/index.js +6 -0
  112. package/lib/cjs/components/theme/index.js.map +1 -0
  113. package/lib/cjs/components/theme/theme.js +147 -0
  114. package/lib/cjs/components/theme/theme.js.map +1 -0
  115. package/lib/cjs/components/theme/types.js +3 -0
  116. package/lib/cjs/components/theme/types.js.map +1 -0
  117. package/lib/cjs/components/toggle/index.js +6 -0
  118. package/lib/cjs/components/toggle/index.js.map +1 -0
  119. package/lib/cjs/components/toggle/toggle.js +139 -0
  120. package/lib/cjs/components/toggle/toggle.js.map +1 -0
  121. package/lib/cjs/components/toggle/types.js +3 -0
  122. package/lib/cjs/components/toggle/types.js.map +1 -0
  123. package/lib/cjs/components/toggle-password/index.js +6 -0
  124. package/lib/cjs/components/toggle-password/index.js.map +1 -0
  125. package/lib/cjs/components/toggle-password/toggle-password.js +131 -0
  126. package/lib/cjs/components/toggle-password/toggle-password.js.map +1 -0
  127. package/lib/cjs/components/toggle-password/types.js +3 -0
  128. package/lib/cjs/components/toggle-password/types.js.map +1 -0
  129. package/lib/cjs/components/tooltip/index.js +6 -0
  130. package/lib/cjs/components/tooltip/index.js.map +1 -0
  131. package/lib/cjs/components/tooltip/tooltip.js +271 -0
  132. package/lib/cjs/components/tooltip/tooltip.js.map +1 -0
  133. package/lib/cjs/components/tooltip/types.js +3 -0
  134. package/lib/cjs/components/tooltip/types.js.map +1 -0
  135. package/lib/cjs/helpers/data.js +33 -0
  136. package/lib/cjs/helpers/data.js.map +1 -0
  137. package/lib/cjs/helpers/dom.js +297 -0
  138. package/lib/cjs/helpers/dom.js.map +1 -0
  139. package/lib/cjs/helpers/event-handler.js +36 -0
  140. package/lib/cjs/helpers/event-handler.js.map +1 -0
  141. package/lib/cjs/helpers/utils.js +94 -0
  142. package/lib/cjs/helpers/utils.js.map +1 -0
  143. package/lib/cjs/index.js +105 -0
  144. package/lib/cjs/index.js.map +1 -0
  145. package/lib/cjs/types.js +3 -0
  146. package/lib/cjs/types.js.map +1 -0
  147. package/lib/esm/components/accordion/accordion.js +165 -0
  148. package/lib/esm/components/accordion/accordion.js.map +1 -0
  149. package/lib/esm/components/accordion/index.js +2 -0
  150. package/lib/esm/components/accordion/index.js.map +1 -0
  151. package/lib/esm/components/accordion/types.js +2 -0
  152. package/lib/esm/components/accordion/types.js.map +1 -0
  153. package/lib/esm/components/collapse/collapse.js +166 -0
  154. package/lib/esm/components/collapse/collapse.js.map +1 -0
  155. package/lib/esm/components/collapse/index.js +2 -0
  156. package/lib/esm/components/collapse/index.js.map +1 -0
  157. package/lib/esm/components/collapse/types.js +2 -0
  158. package/lib/esm/components/collapse/types.js.map +1 -0
  159. package/lib/esm/components/component.js +133 -0
  160. package/lib/esm/components/component.js.map +1 -0
  161. package/lib/esm/components/config.js +24 -0
  162. package/lib/esm/components/config.js.map +1 -0
  163. package/lib/esm/components/config.umd.js +23 -0
  164. package/lib/esm/components/config.umd.js.map +1 -0
  165. package/lib/esm/components/constants.js +12 -0
  166. package/lib/esm/components/constants.js.map +1 -0
  167. package/lib/esm/components/datatable/datatable.js +1461 -0
  168. package/lib/esm/components/datatable/datatable.js.map +1 -0
  169. package/lib/esm/components/datatable/index.js +2 -0
  170. package/lib/esm/components/datatable/index.js.map +1 -0
  171. package/lib/esm/components/datatable/types.js +2 -0
  172. package/lib/esm/components/datatable/types.js.map +1 -0
  173. package/lib/esm/components/dismiss/dismiss.js +128 -0
  174. package/lib/esm/components/dismiss/dismiss.js.map +1 -0
  175. package/lib/esm/components/dismiss/index.js +2 -0
  176. package/lib/esm/components/dismiss/index.js.map +1 -0
  177. package/lib/esm/components/dismiss/types.js +2 -0
  178. package/lib/esm/components/dismiss/types.js.map +1 -0
  179. package/lib/esm/components/drawer/drawer.js +344 -0
  180. package/lib/esm/components/drawer/drawer.js.map +1 -0
  181. package/lib/esm/components/drawer/index.js +2 -0
  182. package/lib/esm/components/drawer/index.js.map +1 -0
  183. package/lib/esm/components/drawer/types.js +2 -0
  184. package/lib/esm/components/drawer/types.js.map +1 -0
  185. package/lib/esm/components/dropdown/dropdown.js +400 -0
  186. package/lib/esm/components/dropdown/dropdown.js.map +1 -0
  187. package/lib/esm/components/dropdown/index.js +2 -0
  188. package/lib/esm/components/dropdown/index.js.map +1 -0
  189. package/lib/esm/components/dropdown/types.js +2 -0
  190. package/lib/esm/components/dropdown/types.js.map +1 -0
  191. package/lib/esm/components/image-input/image-input.js +188 -0
  192. package/lib/esm/components/image-input/image-input.js.map +1 -0
  193. package/lib/esm/components/image-input/index.js +2 -0
  194. package/lib/esm/components/image-input/index.js.map +1 -0
  195. package/lib/esm/components/image-input/types.js +2 -0
  196. package/lib/esm/components/image-input/types.js.map +1 -0
  197. package/lib/esm/components/menu/index.js +2 -0
  198. package/lib/esm/components/menu/index.js.map +1 -0
  199. package/lib/esm/components/menu/menu.js +1018 -0
  200. package/lib/esm/components/menu/menu.js.map +1 -0
  201. package/lib/esm/components/menu/types.js +2 -0
  202. package/lib/esm/components/menu/types.js.map +1 -0
  203. package/lib/esm/components/modal/index.js +2 -0
  204. package/lib/esm/components/modal/index.js.map +1 -0
  205. package/lib/esm/components/modal/modal.js +313 -0
  206. package/lib/esm/components/modal/modal.js.map +1 -0
  207. package/lib/esm/components/modal/types.js +2 -0
  208. package/lib/esm/components/modal/types.js.map +1 -0
  209. package/lib/esm/components/reparent/index.js +2 -0
  210. package/lib/esm/components/reparent/index.js.map +1 -0
  211. package/lib/esm/components/reparent/reparent.js +90 -0
  212. package/lib/esm/components/reparent/reparent.js.map +1 -0
  213. package/lib/esm/components/reparent/types.js +2 -0
  214. package/lib/esm/components/reparent/types.js.map +1 -0
  215. package/lib/esm/components/scrollable/index.js +2 -0
  216. package/lib/esm/components/scrollable/index.js.map +1 -0
  217. package/lib/esm/components/scrollable/scrollable.js +256 -0
  218. package/lib/esm/components/scrollable/scrollable.js.map +1 -0
  219. package/lib/esm/components/scrollable/types.js +2 -0
  220. package/lib/esm/components/scrollable/types.js.map +1 -0
  221. package/lib/esm/components/scrollspy/index.js +2 -0
  222. package/lib/esm/components/scrollspy/index.js.map +1 -0
  223. package/lib/esm/components/scrollspy/scrollspy.js +171 -0
  224. package/lib/esm/components/scrollspy/scrollspy.js.map +1 -0
  225. package/lib/esm/components/scrollspy/types.js +2 -0
  226. package/lib/esm/components/scrollspy/types.js.map +1 -0
  227. package/lib/esm/components/scrollto/index.js +2 -0
  228. package/lib/esm/components/scrollto/index.js.map +1 -0
  229. package/lib/esm/components/scrollto/scrollto.js +100 -0
  230. package/lib/esm/components/scrollto/scrollto.js.map +1 -0
  231. package/lib/esm/components/scrollto/types.js +2 -0
  232. package/lib/esm/components/scrollto/types.js.map +1 -0
  233. package/lib/esm/components/stepper/index.js +2 -0
  234. package/lib/esm/components/stepper/index.js.map +1 -0
  235. package/lib/esm/components/stepper/stepper.js +255 -0
  236. package/lib/esm/components/stepper/stepper.js.map +1 -0
  237. package/lib/esm/components/stepper/types.js +2 -0
  238. package/lib/esm/components/stepper/types.js.map +1 -0
  239. package/lib/esm/components/sticky/index.js +2 -0
  240. package/lib/esm/components/sticky/index.js.map +1 -0
  241. package/lib/esm/components/sticky/sticky.js +294 -0
  242. package/lib/esm/components/sticky/sticky.js.map +1 -0
  243. package/lib/esm/components/sticky/types.js +2 -0
  244. package/lib/esm/components/sticky/types.js.map +1 -0
  245. package/lib/esm/components/tabs/index.js +2 -0
  246. package/lib/esm/components/tabs/index.js.map +1 -0
  247. package/lib/esm/components/tabs/tabs.js +143 -0
  248. package/lib/esm/components/tabs/tabs.js.map +1 -0
  249. package/lib/esm/components/tabs/types.js +2 -0
  250. package/lib/esm/components/tabs/types.js.map +1 -0
  251. package/lib/esm/components/theme/index.js +2 -0
  252. package/lib/esm/components/theme/index.js.map +1 -0
  253. package/lib/esm/components/theme/theme.js +144 -0
  254. package/lib/esm/components/theme/theme.js.map +1 -0
  255. package/lib/esm/components/theme/types.js +2 -0
  256. package/lib/esm/components/theme/types.js.map +1 -0
  257. package/lib/esm/components/toggle/index.js +2 -0
  258. package/lib/esm/components/toggle/index.js.map +1 -0
  259. package/lib/esm/components/toggle/toggle.js +136 -0
  260. package/lib/esm/components/toggle/toggle.js.map +1 -0
  261. package/lib/esm/components/toggle/types.js +2 -0
  262. package/lib/esm/components/toggle/types.js.map +1 -0
  263. package/lib/esm/components/toggle-password/index.js +2 -0
  264. package/lib/esm/components/toggle-password/index.js.map +1 -0
  265. package/lib/esm/components/toggle-password/toggle-password.js +128 -0
  266. package/lib/esm/components/toggle-password/toggle-password.js.map +1 -0
  267. package/lib/esm/components/toggle-password/types.js +2 -0
  268. package/lib/esm/components/toggle-password/types.js.map +1 -0
  269. package/lib/esm/components/tooltip/index.js +2 -0
  270. package/lib/esm/components/tooltip/index.js.map +1 -0
  271. package/lib/esm/components/tooltip/tooltip.js +268 -0
  272. package/lib/esm/components/tooltip/tooltip.js.map +1 -0
  273. package/lib/esm/components/tooltip/types.js +2 -0
  274. package/lib/esm/components/tooltip/types.js.map +1 -0
  275. package/lib/esm/helpers/data.js +31 -0
  276. package/lib/esm/helpers/data.js.map +1 -0
  277. package/lib/esm/helpers/dom.js +295 -0
  278. package/lib/esm/helpers/dom.js.map +1 -0
  279. package/lib/esm/helpers/event-handler.js +34 -0
  280. package/lib/esm/helpers/event-handler.js.map +1 -0
  281. package/lib/esm/helpers/utils.js +92 -0
  282. package/lib/esm/helpers/utils.js.map +1 -0
  283. package/lib/esm/index.js +79 -0
  284. package/lib/esm/index.js.map +1 -0
  285. package/lib/esm/types.js +2 -0
  286. package/lib/esm/types.js.map +1 -0
  287. package/package.json +85 -0
  288. package/prettier.config.js +9 -0
  289. package/src/components/accordion/accordion-menu.css +51 -0
  290. package/src/components/accordion/accordion.css +86 -0
  291. package/src/components/accordion/accordion.ts +221 -0
  292. package/src/components/accordion/index.ts +7 -0
  293. package/src/components/accordion/types.ts +16 -0
  294. package/src/components/alert/alert.css +282 -0
  295. package/src/components/avatar/avatar.css +46 -0
  296. package/src/components/badge/badge.css +176 -0
  297. package/src/components/breadcrumb/breadcrumb.css +38 -0
  298. package/src/components/btn/btn.css +227 -0
  299. package/src/components/card/card.css +158 -0
  300. package/src/components/checkbox/checkbox.css +74 -0
  301. package/src/components/collapse/collapse.css +14 -0
  302. package/src/components/collapse/collapse.ts +200 -0
  303. package/src/components/collapse/index.ts +7 -0
  304. package/src/components/collapse/types.ts +16 -0
  305. package/src/components/component.ts +132 -0
  306. package/src/components/constants.ts +16 -0
  307. package/src/components/datatable/datatable-checkbox.ts +236 -0
  308. package/src/components/datatable/datatable-sort.ts +154 -0
  309. package/src/components/datatable/datatable.css +110 -0
  310. package/src/components/datatable/datatable.ts +1657 -0
  311. package/src/components/datatable/index.ts +19 -0
  312. package/src/components/datatable/types.ts +203 -0
  313. package/src/components/datepicker/calendar.ts +1397 -0
  314. package/src/components/datepicker/config.ts +368 -0
  315. package/src/components/datepicker/datepicker.css +7 -0
  316. package/src/components/datepicker/datepicker.ts +1287 -0
  317. package/src/components/datepicker/dropdown.ts +757 -0
  318. package/src/components/datepicker/events.ts +149 -0
  319. package/src/components/datepicker/index.ts +10 -0
  320. package/src/components/datepicker/keyboard.ts +646 -0
  321. package/src/components/datepicker/locales.ts +80 -0
  322. package/src/components/datepicker/templates.ts +792 -0
  323. package/src/components/datepicker/types.ts +154 -0
  324. package/src/components/datepicker/utils.ts +631 -0
  325. package/src/components/dismiss/dismiss.css +10 -0
  326. package/src/components/dismiss/dismiss.ts +152 -0
  327. package/src/components/dismiss/index.ts +7 -0
  328. package/src/components/dismiss/types.ts +17 -0
  329. package/src/components/drawer/drawer.css +97 -0
  330. package/src/components/drawer/drawer.ts +437 -0
  331. package/src/components/drawer/index.ts +7 -0
  332. package/src/components/drawer/types.ts +25 -0
  333. package/src/components/dropdown/dropdown-menu.css +56 -0
  334. package/src/components/dropdown/dropdown.css +46 -0
  335. package/src/components/dropdown/dropdown.ts +549 -0
  336. package/src/components/dropdown/index.ts +7 -0
  337. package/src/components/dropdown/types.ts +28 -0
  338. package/src/components/form/form.css +54 -0
  339. package/src/components/image-input/image-input.css +56 -0
  340. package/src/components/image-input/image-input.ts +249 -0
  341. package/src/components/image-input/index.ts +10 -0
  342. package/src/components/image-input/types.ts +12 -0
  343. package/src/components/input/input-group.css +42 -0
  344. package/src/components/input/input.css +136 -0
  345. package/src/components/kbd/kbd.css +30 -0
  346. package/src/components/label/label.css +20 -0
  347. package/src/components/link/link.css +81 -0
  348. package/src/components/modal/index.ts +7 -0
  349. package/src/components/modal/modal.css +73 -0
  350. package/src/components/modal/modal.ts +382 -0
  351. package/src/components/modal/types.ts +21 -0
  352. package/src/components/pagination/pagination.css +26 -0
  353. package/src/components/popover/popover.css +22 -0
  354. package/src/components/progress/progress.css +51 -0
  355. package/src/components/radio/radio.css +51 -0
  356. package/src/components/reparent/index.ts +7 -0
  357. package/src/components/reparent/reparent.ts +109 -0
  358. package/src/components/reparent/types.ts +15 -0
  359. package/src/components/scrollable/index.ts +10 -0
  360. package/src/components/scrollable/scrollable.css +29 -0
  361. package/src/components/scrollable/scrollable.ts +297 -0
  362. package/src/components/scrollable/types.ts +16 -0
  363. package/src/components/scrollspy/index.ts +7 -0
  364. package/src/components/scrollspy/scrollspy.css +13 -0
  365. package/src/components/scrollspy/scrollspy.ts +224 -0
  366. package/src/components/scrollspy/types.ts +15 -0
  367. package/src/components/scrollto/index.ts +7 -0
  368. package/src/components/scrollto/scrollto.ts +127 -0
  369. package/src/components/scrollto/types.ts +15 -0
  370. package/src/components/select/combobox.ts +305 -0
  371. package/src/components/select/config.ts +324 -0
  372. package/src/components/select/dropdown.ts +510 -0
  373. package/src/components/select/index.ts +13 -0
  374. package/src/components/select/option.ts +43 -0
  375. package/src/components/select/remote.ts +477 -0
  376. package/src/components/select/search.ts +430 -0
  377. package/src/components/select/select.css +105 -0
  378. package/src/components/select/select.ts +1916 -0
  379. package/src/components/select/tags.ts +123 -0
  380. package/src/components/select/templates.ts +531 -0
  381. package/src/components/select/types.ts +36 -0
  382. package/src/components/select/utils.ts +747 -0
  383. package/src/components/select/variants.css +5 -0
  384. package/src/components/separator/separator.css +14 -0
  385. package/src/components/skeleton/skeleton.css +10 -0
  386. package/src/components/stepper/index.ts +7 -0
  387. package/src/components/stepper/stepper.css +49 -0
  388. package/src/components/stepper/stepper.ts +308 -0
  389. package/src/components/stepper/types.ts +13 -0
  390. package/src/components/sticky/index.ts +7 -0
  391. package/src/components/sticky/sticky.css +22 -0
  392. package/src/components/sticky/sticky.ts +381 -0
  393. package/src/components/sticky/types.ts +23 -0
  394. package/src/components/switch/switch.css +110 -0
  395. package/src/components/table/table.css +168 -0
  396. package/src/components/tabs/index.ts +7 -0
  397. package/src/components/tabs/tabs.css +40 -0
  398. package/src/components/tabs/tabs.ts +190 -0
  399. package/src/components/tabs/types.ts +13 -0
  400. package/src/components/textarea/textarea.css +35 -0
  401. package/src/components/theme-switch/index.ts +10 -0
  402. package/src/components/theme-switch/theme-switch.css +22 -0
  403. package/src/components/theme-switch/theme-switch.ts +176 -0
  404. package/src/components/theme-switch/types.ts +15 -0
  405. package/src/components/toggle/index.ts +7 -0
  406. package/src/components/toggle/toggle.css +13 -0
  407. package/src/components/toggle/toggle.ts +173 -0
  408. package/src/components/toggle/types.ts +18 -0
  409. package/src/components/toggle-group/toggle-group.css +55 -0
  410. package/src/components/toggle-password/index.ts +10 -0
  411. package/src/components/toggle-password/toggle-password.css +13 -0
  412. package/src/components/toggle-password/toggle-password.ts +159 -0
  413. package/src/components/toggle-password/types.ts +13 -0
  414. package/src/components/tooltip/index.ts +7 -0
  415. package/src/components/tooltip/tooltip.css +18 -0
  416. package/src/components/tooltip/tooltip.ts +361 -0
  417. package/src/components/tooltip/types.ts +28 -0
  418. package/src/helpers/data.ts +46 -0
  419. package/src/helpers/dom.ts +405 -0
  420. package/src/helpers/event-handler.ts +61 -0
  421. package/src/helpers/utils.ts +183 -0
  422. package/src/index.ts +113 -0
  423. package/src/types.ts +23 -0
  424. package/styles.css +48 -0
  425. package/tsconfig.json +17 -0
  426. package/webpack.config.js +113 -0
@@ -0,0 +1,1287 @@
1
+ /**
2
+ * KTUI - Free & Open-Source Tailwind UI Components by Keenthemes
3
+ * Copyright 2025 by Keenthemes Inc
4
+ * @version: 1.0.0
5
+ */
6
+ import KTComponent from '../component';
7
+ import { KTDatepickerCalendar } from './calendar';
8
+ import { KTDatepickerStateManager } from './config';
9
+ import { KTDatepickerKeyboard } from './keyboard';
10
+ import { DateRangeInterface, KTDatepickerConfigInterface } from './types';
11
+ import { formatDate, parseDate, isValidDate, isDateDisabled } from './utils';
12
+ import {
13
+ datepickerContainerTemplate,
14
+ inputWrapperTemplate,
15
+ segmentedDateInputTemplate,
16
+ segmentedDateRangeInputTemplate,
17
+ placeholderTemplate,
18
+ } from './templates';
19
+ import { KTDatepickerEventManager, KTDatepickerEventName } from './events';
20
+
21
+ // Helper function to replace stringToElement
22
+ function createElement(html: string): HTMLElement {
23
+ const template = document.createElement('template');
24
+ template.innerHTML = html.trim();
25
+ return template.content.firstChild as HTMLElement;
26
+ }
27
+
28
+ /**
29
+ * KTDatepicker - Main datepicker component class
30
+ * Manages the datepicker functionality and integration with input elements
31
+ */
32
+ export class KTDatepicker extends KTComponent {
33
+ protected override readonly _name: string = 'datepicker';
34
+ protected override readonly _config: KTDatepickerConfigInterface;
35
+
36
+ private _state: KTDatepickerStateManager;
37
+ private _calendar: KTDatepickerCalendar;
38
+ private _keyboard: KTDatepickerKeyboard;
39
+ private _eventManager: KTDatepickerEventManager;
40
+
41
+ private _dateInputElement: HTMLInputElement | null = null;
42
+ private _startDateInputElement: HTMLInputElement | null = null;
43
+ private _endDateInputElement: HTMLInputElement | null = null;
44
+ private _displayElement: HTMLElement | null = null;
45
+ private _useSegmentedDisplay = false;
46
+ private _displayWrapper: HTMLElement | null = null;
47
+ private _displayText: HTMLElement | null = null;
48
+
49
+ private _currentDate: Date | null = null;
50
+ private _currentRange: DateRangeInterface | null = null;
51
+ private _segmentFocused:
52
+ | 'day'
53
+ | 'month'
54
+ | 'year'
55
+ | 'start-day'
56
+ | 'start-month'
57
+ | 'start-year'
58
+ | 'end-day'
59
+ | 'end-month'
60
+ | 'end-year'
61
+ | null = null;
62
+
63
+ /**
64
+ * Constructor for the KTDatepicker class.
65
+ */
66
+ constructor(element: HTMLElement, config?: KTDatepickerConfigInterface) {
67
+ super();
68
+
69
+ // Check if the element already has a datepicker instance attached to it
70
+ if (element.getAttribute('data-kt-datepicker-initialized') === 'true') {
71
+ return;
72
+ }
73
+
74
+ // Initialize the datepicker with the provided element
75
+ this._init(element);
76
+
77
+ // Build the configuration object by merging the default config with the provided config
78
+ this._buildConfig(config);
79
+
80
+ // Store the instance of the datepicker directly on the element
81
+ (element as any).instance = this;
82
+
83
+ // Ensure the element is focusable
84
+ this._element.setAttribute('tabindex', '0');
85
+ this._element.classList.add(
86
+ 'kt-datepicker',
87
+ 'relative',
88
+ 'focus:outline-none',
89
+ );
90
+
91
+ // Mark as initialized
92
+ this._element.setAttribute('data-kt-datepicker-initialized', 'true');
93
+
94
+ // Find input elements
95
+ this._initializeInputElements();
96
+
97
+ // Create display element if needed
98
+ this._createDisplayElement();
99
+
100
+ // Create state manager first
101
+ this._state = new KTDatepickerStateManager(this._element, this._config);
102
+ this._config = this._state.getConfig();
103
+
104
+ // Initialize the calendar and keyboard after creating the state manager
105
+ this._calendar = new KTDatepickerCalendar(this._element, this._state);
106
+ this._keyboard = new KTDatepickerKeyboard(this._element, this._state);
107
+
108
+ // Initialize event manager
109
+ this._eventManager = this._state.getEventManager();
110
+
111
+ // Set up event listeners
112
+ this._setupEventListeners();
113
+
114
+ // Initialize with any default values
115
+ this._initializeDefaultValues();
116
+ }
117
+
118
+ /**
119
+ * Initialize input elements
120
+ */
121
+ private _initializeInputElements(): void {
122
+ // Get main input element - will be hidden
123
+ this._dateInputElement = this._element.querySelector(
124
+ '[data-kt-datepicker-input]',
125
+ );
126
+
127
+ // Hide the input element and make it only for data storage
128
+ if (this._dateInputElement) {
129
+ this._dateInputElement.classList.add('hidden', 'sr-only');
130
+ this._dateInputElement.setAttribute('aria-hidden', 'true');
131
+ this._dateInputElement.tabIndex = -1;
132
+ }
133
+
134
+ // Get range input elements if applicable
135
+ this._startDateInputElement = this._element.querySelector(
136
+ '[data-kt-datepicker-start]',
137
+ );
138
+ this._endDateInputElement = this._element.querySelector(
139
+ '[data-kt-datepicker-end]',
140
+ );
141
+
142
+ // Get display element if exists
143
+ this._displayElement = this._element.querySelector(
144
+ '[data-kt-datepicker-display]',
145
+ );
146
+
147
+ // Check if we should use segmented display
148
+ this._useSegmentedDisplay =
149
+ this._element.hasAttribute('data-kt-datepicker-segmented') ||
150
+ this._element.hasAttribute('data-kt-datepicker-segmented-input');
151
+ }
152
+
153
+ /**
154
+ * Create display element for datepicker
155
+ */
156
+ private _createDisplayElement(): void {
157
+ // Skip if already created
158
+ if (this._displayElement) {
159
+ return;
160
+ }
161
+
162
+ // Get format from config or use default
163
+ const format = this._config.format || 'mm/dd/yyyy';
164
+ const placeholder =
165
+ this._dateInputElement?.getAttribute('placeholder') || format;
166
+
167
+ // Create wrapper for display element
168
+ this._displayWrapper = document.createElement('div');
169
+ this._displayWrapper.className =
170
+ 'kt-datepicker-display-wrapper kt-datepicker-display-segment';
171
+ this._displayWrapper.setAttribute('role', 'combobox');
172
+ this._displayWrapper.setAttribute('aria-haspopup', 'dialog');
173
+ this._displayWrapper.setAttribute('aria-expanded', 'false');
174
+ this._element.appendChild(this._displayWrapper);
175
+
176
+ if (this._useSegmentedDisplay) {
177
+ // Create segmented display for better date part selection
178
+ const displayContainer = document.createElement('div');
179
+ displayContainer.className = 'kt-datepicker-display-element';
180
+ displayContainer.setAttribute('tabindex', '0');
181
+ displayContainer.setAttribute('role', 'textbox');
182
+ displayContainer.setAttribute('aria-label', placeholder);
183
+ displayContainer.setAttribute('data-kt-datepicker-display', '');
184
+
185
+ // Add segmented template based on range mode
186
+ if (this._config.range) {
187
+ displayContainer.innerHTML = segmentedDateRangeInputTemplate(
188
+ this._config.format || 'mm/dd/yyyy',
189
+ );
190
+ } else {
191
+ displayContainer.innerHTML = segmentedDateInputTemplate(
192
+ this._config.format || 'mm/dd/yyyy',
193
+ );
194
+ }
195
+
196
+ this._displayElement = displayContainer;
197
+ this._displayWrapper.appendChild(this._displayElement);
198
+
199
+ // Add click handlers for segments
200
+ const segments = this._displayElement.querySelectorAll('[data-segment]');
201
+ segments.forEach((segment) => {
202
+ segment.addEventListener('click', (e) => {
203
+ e.stopPropagation();
204
+ const segmentType = segment.getAttribute('data-segment');
205
+ this._handleSegmentClick(segmentType);
206
+ });
207
+ });
208
+ } else {
209
+ // Create simple display element
210
+ this._displayElement = document.createElement('div');
211
+ this._displayElement.className = 'kt-datepicker-display-element';
212
+ this._displayElement.setAttribute('tabindex', '0');
213
+ this._displayElement.setAttribute('role', 'textbox');
214
+ this._displayElement.setAttribute('aria-label', placeholder);
215
+ this._displayElement.setAttribute('data-placeholder', placeholder);
216
+ this._displayElement.setAttribute('data-kt-datepicker-display', '');
217
+
218
+ // Create display text element
219
+ this._displayText = document.createElement('span');
220
+ this._displayText.className = 'kt-datepicker-display-text';
221
+ this._displayText.textContent = placeholder;
222
+ this._displayText.classList.add('text-gray-400');
223
+
224
+ this._displayElement.appendChild(this._displayText);
225
+ this._displayWrapper.appendChild(this._displayElement);
226
+ }
227
+
228
+ // Add click event to display element
229
+ this._displayElement.addEventListener('click', (e) => {
230
+ e.preventDefault();
231
+ if (!this._state.getState().isOpen) {
232
+ this._state.setOpen(true);
233
+ }
234
+ });
235
+
236
+ // Enhanced keyboard event handling for display element
237
+ this._displayElement.addEventListener('keydown', (e) => {
238
+ if (e.key === 'Enter' || e.key === ' ' || e.key === 'ArrowDown') {
239
+ e.preventDefault();
240
+ e.stopPropagation();
241
+
242
+ // If not already open, open the dropdown
243
+ if (!this._state.getState().isOpen) {
244
+ this._state.setOpen(true);
245
+
246
+ // Dispatch a custom event to notify about the keyboard open
247
+ this._eventManager.dispatchKeyboardOpenEvent();
248
+ }
249
+ }
250
+ });
251
+ }
252
+
253
+ /**
254
+ * Handle segment click to focus and open appropriate view
255
+ *
256
+ * @param segmentType - Type of segment clicked
257
+ */
258
+ private _handleSegmentClick(segmentType: string | null): void {
259
+ if (!segmentType) return;
260
+
261
+ // Store the focused segment
262
+ this._segmentFocused = segmentType as any;
263
+
264
+ // Remove highlight from all segments
265
+ this._removeSegmentHighlights();
266
+
267
+ // Add highlight to clicked segment
268
+ if (this._displayElement) {
269
+ const segment = this._displayElement.querySelector(
270
+ `[data-segment="${segmentType}"]`,
271
+ );
272
+ if (segment) {
273
+ segment.classList.add('kt-datepicker-segment-focused');
274
+ }
275
+ }
276
+
277
+ // Set the appropriate view mode based on segment type
278
+ if (segmentType.includes('day')) {
279
+ // Day segment - open in days view (default)
280
+ this._state.setViewMode('days');
281
+ this._state.setOpen(true);
282
+ } else if (segmentType.includes('month')) {
283
+ // Month segment - open in months view
284
+ this._state.setViewMode('months');
285
+ this._state.setOpen(true);
286
+ } else if (segmentType.includes('year')) {
287
+ // Year segment - open in years view
288
+ this._state.setViewMode('years');
289
+ this._state.setOpen(true);
290
+ }
291
+ }
292
+
293
+ /**
294
+ * Set up event listeners
295
+ */
296
+ private _setupEventListeners(): void {
297
+ // Listen for state changes
298
+ this._eventManager.addEventListener(
299
+ KTDatepickerEventName.STATE_CHANGE,
300
+ (e: CustomEvent) => {
301
+ const { state } = e.detail;
302
+
303
+ // Update ARIA attributes based on open state
304
+ if (this._displayWrapper) {
305
+ this._displayWrapper.setAttribute(
306
+ 'aria-expanded',
307
+ state.isOpen.toString(),
308
+ );
309
+ }
310
+
311
+ // Update display when closing
312
+ if (!state.isOpen && state.prevIsOpen) {
313
+ this._syncDisplayWithSelectedDate();
314
+ }
315
+ },
316
+ );
317
+
318
+ // Set up change event listener to update input values
319
+ this._eventManager.addEventListener(
320
+ KTDatepickerEventName.DATE_CHANGE,
321
+ this._handleDateChange.bind(this),
322
+ );
323
+
324
+ // Add keyboard events to the root element
325
+ this._element.addEventListener('keydown', (e) => {
326
+ if (e.key === 'Enter' || e.key === ' ' || e.key === 'ArrowDown') {
327
+ const state = this._state.getState();
328
+ if (!state.isOpen) {
329
+ e.preventDefault();
330
+ this._state.setOpen(true);
331
+ }
332
+ }
333
+ });
334
+
335
+ // Add keyboard navigation for segments
336
+ if (this._displayElement && this._useSegmentedDisplay) {
337
+ this._displayElement.addEventListener(
338
+ 'keydown',
339
+ this._handleSegmentKeydown.bind(this),
340
+ );
341
+ }
342
+ }
343
+
344
+ /**
345
+ * Handle keyboard navigation between segments
346
+ *
347
+ * @param e - Keyboard event
348
+ */
349
+ private _handleSegmentKeydown(e: KeyboardEvent): void {
350
+ // Only handle if we have a focused segment
351
+ if (!this._segmentFocused) return;
352
+
353
+ const target = e.target as HTMLElement;
354
+ const segmentType = target.getAttribute('data-segment');
355
+ if (!segmentType) return;
356
+
357
+ // Handle keyboard navigation
358
+ switch (e.key) {
359
+ case 'ArrowLeft':
360
+ e.preventDefault();
361
+ this._navigateSegments('prev', segmentType);
362
+ break;
363
+ case 'ArrowRight':
364
+ e.preventDefault();
365
+ this._navigateSegments('next', segmentType);
366
+ break;
367
+ case 'Tab':
368
+ // Let default tab behavior work, but update focus segment when tabbing
369
+ this._segmentFocused = segmentType as any;
370
+ // Remove highlight from all segments
371
+ this._removeSegmentHighlights();
372
+ // Add highlight to current segment
373
+ target.classList.add('segment-focused');
374
+ break;
375
+ case 'Enter':
376
+ case ' ':
377
+ e.preventDefault();
378
+ this._handleSegmentClick(segmentType);
379
+ break;
380
+ }
381
+ }
382
+
383
+ /**
384
+ * Navigate between segments with keyboard
385
+ *
386
+ * @param direction - 'prev' or 'next'
387
+ * @param currentSegment - Current segment identifier
388
+ */
389
+ private _navigateSegments(
390
+ direction: 'prev' | 'next',
391
+ currentSegment: string,
392
+ ): void {
393
+ if (!this._displayElement) return;
394
+
395
+ // Define segment order
396
+ let segments: string[];
397
+ if (this._config.range) {
398
+ segments = [
399
+ 'start-month',
400
+ 'start-day',
401
+ 'start-year',
402
+ 'end-month',
403
+ 'end-day',
404
+ 'end-year',
405
+ ];
406
+ } else {
407
+ segments = ['month', 'day', 'year'];
408
+ }
409
+
410
+ // Find current index
411
+ const currentIndex = segments.indexOf(currentSegment);
412
+ if (currentIndex === -1) return;
413
+
414
+ // Calculate new index
415
+ let newIndex;
416
+ if (direction === 'prev') {
417
+ newIndex = currentIndex === 0 ? segments.length - 1 : currentIndex - 1;
418
+ } else {
419
+ newIndex = currentIndex === segments.length - 1 ? 0 : currentIndex + 1;
420
+ }
421
+
422
+ // Find new segment element
423
+ const newSegment = this._displayElement.querySelector(
424
+ `[data-segment="${segments[newIndex]}"]`,
425
+ ) as HTMLElement;
426
+ if (!newSegment) return;
427
+
428
+ // Update focus
429
+ newSegment.focus();
430
+ this._segmentFocused = segments[newIndex] as any;
431
+
432
+ // Remove highlight from all segments
433
+ this._removeSegmentHighlights();
434
+
435
+ // Add highlight to new segment
436
+ newSegment.classList.add('segment-focused');
437
+ }
438
+
439
+ /**
440
+ * Remove highlight from all segments
441
+ */
442
+ private _removeSegmentHighlights(): void {
443
+ if (!this._displayElement) return;
444
+
445
+ const segments = this._displayElement.querySelectorAll('.segment-part');
446
+ segments.forEach((segment) => {
447
+ segment.classList.remove('segment-focused');
448
+ });
449
+ }
450
+
451
+ /**
452
+ * Sync display element with the selected date
453
+ */
454
+ private _syncDisplayWithSelectedDate(): void {
455
+ if (!this._displayElement) return;
456
+
457
+ const state = this._state.getState();
458
+ const selectedDate = state.selectedDate;
459
+ const selectedDateRange = state.selectedDateRange;
460
+
461
+ if (this._useSegmentedDisplay) {
462
+ // Update segmented display elements
463
+ if (selectedDate) {
464
+ // Single date
465
+ const daySegment = this._displayElement.querySelector(
466
+ '[data-segment="day"]',
467
+ );
468
+ const monthSegment = this._displayElement.querySelector(
469
+ '[data-segment="month"]',
470
+ );
471
+ const yearSegment = this._displayElement.querySelector(
472
+ '[data-segment="year"]',
473
+ );
474
+
475
+ if (daySegment) {
476
+ daySegment.textContent = selectedDate
477
+ .getDate()
478
+ .toString()
479
+ .padStart(2, '0');
480
+ }
481
+ if (monthSegment) {
482
+ monthSegment.textContent = (selectedDate.getMonth() + 1)
483
+ .toString()
484
+ .padStart(2, '0');
485
+ }
486
+ if (yearSegment) {
487
+ yearSegment.textContent = selectedDate.getFullYear().toString();
488
+ }
489
+ } else if (selectedDateRange && selectedDateRange.startDate) {
490
+ // Range selection
491
+ const startDay = this._displayElement.querySelector(
492
+ '[data-segment="start-day"]',
493
+ );
494
+ const startMonth = this._displayElement.querySelector(
495
+ '[data-segment="start-month"]',
496
+ );
497
+ const startYear = this._displayElement.querySelector(
498
+ '[data-segment="start-year"]',
499
+ );
500
+
501
+ if (startDay) {
502
+ startDay.textContent = selectedDateRange.startDate
503
+ .getDate()
504
+ .toString()
505
+ .padStart(2, '0');
506
+ }
507
+ if (startMonth) {
508
+ startMonth.textContent = (selectedDateRange.startDate.getMonth() + 1)
509
+ .toString()
510
+ .padStart(2, '0');
511
+ }
512
+ if (startYear) {
513
+ startYear.textContent = selectedDateRange.startDate
514
+ .getFullYear()
515
+ .toString();
516
+ }
517
+
518
+ if (selectedDateRange.endDate) {
519
+ const endDay = this._displayElement.querySelector(
520
+ '[data-segment="end-day"]',
521
+ );
522
+ const endMonth = this._displayElement.querySelector(
523
+ '[data-segment="end-month"]',
524
+ );
525
+ const endYear = this._displayElement.querySelector(
526
+ '[data-segment="end-year"]',
527
+ );
528
+
529
+ if (endDay) {
530
+ endDay.textContent = selectedDateRange.endDate
531
+ .getDate()
532
+ .toString()
533
+ .padStart(2, '0');
534
+ }
535
+ if (endMonth) {
536
+ endMonth.textContent = (selectedDateRange.endDate.getMonth() + 1)
537
+ .toString()
538
+ .padStart(2, '0');
539
+ }
540
+ if (endYear) {
541
+ endYear.textContent = selectedDateRange.endDate
542
+ .getFullYear()
543
+ .toString();
544
+ }
545
+ }
546
+ }
547
+ } else if (this._displayText) {
548
+ // Simple display
549
+ if (selectedDate) {
550
+ // Clear placeholder styling
551
+ this._displayText.classList.remove('placeholder');
552
+
553
+ // Format date(s) based on config
554
+ if (
555
+ this._config.range &&
556
+ selectedDateRange &&
557
+ selectedDateRange.startDate &&
558
+ selectedDateRange.endDate
559
+ ) {
560
+ this._displayText.textContent = `${formatDate(
561
+ selectedDateRange.startDate,
562
+ this._config.format,
563
+ this._config,
564
+ )} - ${formatDate(
565
+ selectedDateRange.endDate,
566
+ this._config.format,
567
+ this._config,
568
+ )}`;
569
+ } else {
570
+ this._displayText.textContent = formatDate(
571
+ selectedDate,
572
+ this._config.format,
573
+ this._config,
574
+ );
575
+ }
576
+ } else {
577
+ // No date selected, show format as placeholder
578
+ const placeholder =
579
+ this._displayElement?.getAttribute('data-placeholder') ||
580
+ this._config.format;
581
+ this._displayText.textContent = placeholder;
582
+ this._displayText.classList.add('placeholder');
583
+ }
584
+ }
585
+ }
586
+
587
+ /**
588
+ * Handle date change events
589
+ *
590
+ * @param e - Custom event with date change details
591
+ */
592
+ private _handleDateChange(e: CustomEvent): void {
593
+ const detail = e.detail?.payload;
594
+ if (!detail) return;
595
+
596
+ // Handle single date selection
597
+ if (detail.selectedDate) {
598
+ const formattedDate = formatDate(
599
+ detail.selectedDate,
600
+ this._config.format,
601
+ this._config,
602
+ );
603
+
604
+ // Update hidden input value
605
+ if (this._dateInputElement) {
606
+ this._dateInputElement.value = formattedDate;
607
+ // Dispatch change event on input to trigger form validation
608
+ this._dateInputElement.dispatchEvent(
609
+ new Event('change', { bubbles: true }),
610
+ );
611
+ }
612
+
613
+ // Update display element
614
+ this._updateDisplayElement(detail.selectedDate);
615
+ }
616
+
617
+ // Handle date range selection
618
+ if (detail.selectedDateRange && this._config.range) {
619
+ const { startDate, endDate } = detail.selectedDateRange;
620
+
621
+ // Format the range for the hidden input
622
+ if (this._dateInputElement) {
623
+ let displayValue = '';
624
+
625
+ if (startDate) {
626
+ displayValue = formatDate(
627
+ startDate,
628
+ this._config.format,
629
+ this._config,
630
+ );
631
+
632
+ if (endDate) {
633
+ const endFormatted = formatDate(
634
+ endDate,
635
+ this._config.format,
636
+ this._config,
637
+ );
638
+ displayValue += `${this._config.rangeSeparator}${endFormatted}`;
639
+ }
640
+ }
641
+
642
+ this._dateInputElement.value = displayValue;
643
+ // Dispatch change event on input
644
+ this._dateInputElement.dispatchEvent(
645
+ new Event('change', { bubbles: true }),
646
+ );
647
+ }
648
+
649
+ // Update individual start/end inputs if they exist
650
+ if (this._startDateInputElement && startDate) {
651
+ this._startDateInputElement.value = formatDate(
652
+ startDate,
653
+ this._config.format,
654
+ this._config,
655
+ );
656
+ this._startDateInputElement.dispatchEvent(
657
+ new Event('change', { bubbles: true }),
658
+ );
659
+ }
660
+
661
+ if (this._endDateInputElement && endDate) {
662
+ this._endDateInputElement.value = formatDate(
663
+ endDate,
664
+ this._config.format,
665
+ this._config,
666
+ );
667
+ this._endDateInputElement.dispatchEvent(
668
+ new Event('change', { bubbles: true }),
669
+ );
670
+ }
671
+
672
+ // Update display element for range
673
+ this._updateRangeDisplayElement(startDate, endDate);
674
+ }
675
+ }
676
+
677
+ /**
678
+ * Update the display element for a single date
679
+ *
680
+ * @param date - The date to display
681
+ */
682
+ private _updateDisplayElement(date: Date | null): void {
683
+ if (!this._displayElement) return;
684
+
685
+ if (!date) {
686
+ // If no date, show placeholder
687
+ const placeholder =
688
+ this._dateInputElement?.getAttribute('placeholder') || 'Select date';
689
+ this._displayElement.innerHTML = placeholderTemplate(placeholder);
690
+ return;
691
+ }
692
+
693
+ if (this._useSegmentedDisplay) {
694
+ // Update segmented display
695
+ const day = date.getDate();
696
+ const month = date.getMonth() + 1;
697
+ const year = date.getFullYear();
698
+
699
+ const daySegment = this._displayElement.querySelector(
700
+ '[data-segment="day"]',
701
+ );
702
+ const monthSegment = this._displayElement.querySelector(
703
+ '[data-segment="month"]',
704
+ );
705
+ const yearSegment = this._displayElement.querySelector(
706
+ '[data-segment="year"]',
707
+ );
708
+
709
+ if (daySegment) daySegment.textContent = day < 10 ? `0${day}` : `${day}`;
710
+ if (monthSegment)
711
+ monthSegment.textContent = month < 10 ? `0${month}` : `${month}`;
712
+ if (yearSegment) yearSegment.textContent = `${year}`;
713
+ } else {
714
+ // Simple display
715
+ this._displayElement.textContent = formatDate(
716
+ date,
717
+ this._config.format,
718
+ this._config,
719
+ );
720
+ }
721
+ }
722
+
723
+ /**
724
+ * Update the display element for a date range
725
+ *
726
+ * @param startDate - The start date of the range
727
+ * @param endDate - The end date of the range
728
+ */
729
+ private _updateRangeDisplayElement(
730
+ startDate: Date | null,
731
+ endDate: Date | null,
732
+ ): void {
733
+ if (!this._displayElement) return;
734
+
735
+ if (!startDate) {
736
+ // If no date, show placeholder
737
+ const placeholder =
738
+ this._dateInputElement?.getAttribute('placeholder') ||
739
+ 'Select date range';
740
+ this._displayElement.innerHTML = placeholderTemplate(placeholder);
741
+ return;
742
+ }
743
+
744
+ if (this._useSegmentedDisplay) {
745
+ // Update segmented range display
746
+ // Start date segments
747
+ const startDay = this._displayElement.querySelector(
748
+ '[data-segment="start-day"]',
749
+ );
750
+ const startMonth = this._displayElement.querySelector(
751
+ '[data-segment="start-month"]',
752
+ );
753
+ const startYear = this._displayElement.querySelector(
754
+ '[data-segment="start-year"]',
755
+ );
756
+
757
+ if (startDay)
758
+ startDay.textContent =
759
+ startDate.getDate() < 10
760
+ ? `0${startDate.getDate()}`
761
+ : `${startDate.getDate()}`;
762
+ if (startMonth)
763
+ startMonth.textContent =
764
+ startDate.getMonth() + 1 < 10
765
+ ? `0${startDate.getMonth() + 1}`
766
+ : `${startDate.getMonth() + 1}`;
767
+ if (startYear) startYear.textContent = `${startDate.getFullYear()}`;
768
+
769
+ // End date segments
770
+ if (endDate) {
771
+ const endDay = this._displayElement.querySelector(
772
+ '[data-segment="end-day"]',
773
+ );
774
+ const endMonth = this._displayElement.querySelector(
775
+ '[data-segment="end-month"]',
776
+ );
777
+ const endYear = this._displayElement.querySelector(
778
+ '[data-segment="end-year"]',
779
+ );
780
+
781
+ if (endDay)
782
+ endDay.textContent =
783
+ endDate.getDate() < 10
784
+ ? `0${endDate.getDate()}`
785
+ : `${endDate.getDate()}`;
786
+ if (endMonth)
787
+ endMonth.textContent =
788
+ endDate.getMonth() + 1 < 10
789
+ ? `0${endDate.getMonth() + 1}`
790
+ : `${endDate.getMonth() + 1}`;
791
+ if (endYear) endYear.textContent = `${endDate.getFullYear()}`;
792
+ }
793
+ } else {
794
+ // Simple display
795
+ let displayText = formatDate(
796
+ startDate,
797
+ this._config.format,
798
+ this._config,
799
+ );
800
+
801
+ if (endDate) {
802
+ const endFormatted = formatDate(
803
+ endDate,
804
+ this._config.format,
805
+ this._config,
806
+ );
807
+ displayText += `${this._config.rangeSeparator}${endFormatted}`;
808
+ }
809
+
810
+ this._displayElement.textContent = displayText;
811
+ }
812
+ }
813
+
814
+ /**
815
+ * Handle input change events
816
+ *
817
+ * @param e - Input change event
818
+ */
819
+ private _handleInputChange(e: Event): void {
820
+ const input = e.target as HTMLInputElement;
821
+ const inputValue = input.value.trim();
822
+
823
+ if (!inputValue) {
824
+ // Clear selection if input is empty
825
+ this._state.setSelectedDate(null);
826
+ return;
827
+ }
828
+
829
+ if (this._config.range) {
830
+ // Handle range input
831
+ const rangeParts = inputValue.split(this._config.rangeSeparator);
832
+
833
+ if (rangeParts.length === 2) {
834
+ const startDate = parseDate(
835
+ rangeParts[0].trim(),
836
+ this._config.format,
837
+ this._config,
838
+ );
839
+ const endDate = parseDate(
840
+ rangeParts[1].trim(),
841
+ this._config.format,
842
+ this._config,
843
+ );
844
+
845
+ // Validate dates are within min/max constraints
846
+ if (startDate && isDateDisabled(startDate, this._config)) {
847
+ console.log(
848
+ 'Start date from input is outside allowed range:',
849
+ startDate.toISOString(),
850
+ );
851
+ return;
852
+ }
853
+
854
+ if (endDate && isDateDisabled(endDate, this._config)) {
855
+ console.log(
856
+ 'End date from input is outside allowed range:',
857
+ endDate.toISOString(),
858
+ );
859
+ return;
860
+ }
861
+
862
+ if (startDate && endDate) {
863
+ this.setDateRange(startDate, endDate);
864
+ }
865
+ } else if (rangeParts.length === 1) {
866
+ const singleDate = parseDate(
867
+ rangeParts[0].trim(),
868
+ this._config.format,
869
+ this._config,
870
+ );
871
+
872
+ // Validate date is within min/max constraints
873
+ if (singleDate && isDateDisabled(singleDate, this._config)) {
874
+ console.log(
875
+ 'Date from input is outside allowed range:',
876
+ singleDate.toISOString(),
877
+ );
878
+ return;
879
+ }
880
+
881
+ if (singleDate) {
882
+ this.setDateRange(singleDate, null);
883
+ }
884
+ }
885
+ } else {
886
+ // Handle single date input
887
+ const parsedDate = parseDate(
888
+ inputValue,
889
+ this._config.format,
890
+ this._config,
891
+ );
892
+
893
+ // Validate date is within min/max constraints
894
+ if (parsedDate && isDateDisabled(parsedDate, this._config)) {
895
+ console.log(
896
+ 'Date from input is outside allowed range:',
897
+ parsedDate.toISOString(),
898
+ );
899
+ return;
900
+ }
901
+
902
+ if (parsedDate) {
903
+ this.setDate(parsedDate);
904
+ }
905
+ }
906
+ }
907
+
908
+ /**
909
+ * Initialize with default values from input
910
+ */
911
+ private _initializeDefaultValues(): void {
912
+ // Set min and max dates from attributes if they exist
913
+ const minDateAttr = this._element.getAttribute(
914
+ 'data-kt-datepicker-min-date',
915
+ );
916
+ const maxDateAttr = this._element.getAttribute(
917
+ 'data-kt-datepicker-max-date',
918
+ );
919
+
920
+ if (minDateAttr) {
921
+ const minDate = parseDate(minDateAttr, this._config.format, this._config);
922
+ if (minDate) {
923
+ this.setMinDate(minDate);
924
+ }
925
+ }
926
+
927
+ if (maxDateAttr) {
928
+ const maxDate = parseDate(maxDateAttr, this._config.format, this._config);
929
+ if (maxDate) {
930
+ this.setMaxDate(maxDate);
931
+ }
932
+ }
933
+
934
+ // Check for default value in main input
935
+ if (this._dateInputElement && this._dateInputElement.value) {
936
+ this._handleInputChange({
937
+ target: this._dateInputElement,
938
+ } as unknown as Event);
939
+ }
940
+ // Check for default values in range inputs
941
+ else if (
942
+ this._config.range &&
943
+ this._startDateInputElement &&
944
+ this._startDateInputElement.value
945
+ ) {
946
+ const startDate = parseDate(
947
+ this._startDateInputElement.value,
948
+ this._config.format,
949
+ this._config,
950
+ );
951
+ let endDate = null;
952
+
953
+ if (this._endDateInputElement && this._endDateInputElement.value) {
954
+ endDate = parseDate(
955
+ this._endDateInputElement.value,
956
+ this._config.format,
957
+ this._config,
958
+ );
959
+ }
960
+
961
+ if (startDate) {
962
+ this.setDateRange(startDate, endDate);
963
+ }
964
+ }
965
+ }
966
+
967
+ /**
968
+ * ========================================================================
969
+ * Public API
970
+ * ========================================================================
971
+ */
972
+
973
+ /**
974
+ * Get the currently selected date
975
+ *
976
+ * @returns Selected date, null if no selection, or date range object
977
+ */
978
+ public getDate(): Date | null | DateRangeInterface {
979
+ const state = this._state.getState();
980
+ const config = this._state.getConfig();
981
+
982
+ if (config.range) {
983
+ return state.selectedDateRange || { startDate: null, endDate: null };
984
+ } else {
985
+ return state.selectedDate;
986
+ }
987
+ }
988
+
989
+ /**
990
+ * Set the selected date
991
+ *
992
+ * @param date - Date to select or null to clear selection
993
+ */
994
+ public setDate(date: Date | null): void {
995
+ // Skip if the date is disabled (outside min/max range)
996
+ if (date && isDateDisabled(date, this._config)) {
997
+ console.log(
998
+ 'Date is disabled in setDate, ignoring selection:',
999
+ date.toISOString(),
1000
+ );
1001
+ return;
1002
+ }
1003
+
1004
+ this._state.setSelectedDate(date);
1005
+
1006
+ if (date) {
1007
+ this._state.setCurrentDate(date);
1008
+ }
1009
+
1010
+ // Update the display
1011
+ this._updateDisplayElement(date);
1012
+
1013
+ // Update hidden input
1014
+ if (this._dateInputElement && date) {
1015
+ this._dateInputElement.value = formatDate(
1016
+ date,
1017
+ this._config.format,
1018
+ this._config,
1019
+ );
1020
+ this._dateInputElement.dispatchEvent(
1021
+ new Event('change', { bubbles: true }),
1022
+ );
1023
+ } else if (this._dateInputElement) {
1024
+ this._dateInputElement.value = '';
1025
+ this._dateInputElement.dispatchEvent(
1026
+ new Event('change', { bubbles: true }),
1027
+ );
1028
+ }
1029
+ }
1030
+
1031
+ /**
1032
+ * Get the currently selected date range
1033
+ *
1034
+ * @returns Selected date range or null if no selection
1035
+ */
1036
+ public getDateRange(): DateRangeInterface | null {
1037
+ const state = this._state.getState();
1038
+ return state.selectedDateRange;
1039
+ }
1040
+
1041
+ /**
1042
+ * Set the selected date range
1043
+ *
1044
+ * @param start - Start date of the range
1045
+ * @param end - End date of the range
1046
+ */
1047
+ public setDateRange(start: Date | null, end: Date | null): void {
1048
+ const state = this._state.getState();
1049
+
1050
+ // Ensure we're in range mode
1051
+ if (!this._config.range) {
1052
+ console.warn('Cannot set date range when range mode is disabled');
1053
+ return;
1054
+ }
1055
+
1056
+ // Validate start and end dates are within min/max range
1057
+ if (start && isDateDisabled(start, this._config)) {
1058
+ console.log(
1059
+ 'Start date is disabled in setDateRange, ignoring selection:',
1060
+ start.toISOString(),
1061
+ );
1062
+ return;
1063
+ }
1064
+
1065
+ if (end && isDateDisabled(end, this._config)) {
1066
+ console.log(
1067
+ 'End date is disabled in setDateRange, ignoring selection:',
1068
+ end.toISOString(),
1069
+ );
1070
+ return;
1071
+ }
1072
+
1073
+ // Reset range selection state
1074
+ this._state.getState().isRangeSelectionStart = true;
1075
+
1076
+ // Set start date
1077
+ if (start) {
1078
+ if (!state.selectedDateRange) {
1079
+ state.selectedDateRange = { startDate: null, endDate: null };
1080
+ }
1081
+
1082
+ state.selectedDateRange.startDate = start;
1083
+ this._state.setCurrentDate(start);
1084
+
1085
+ // Set end date if provided
1086
+ if (end) {
1087
+ state.selectedDateRange.endDate = end;
1088
+ } else {
1089
+ state.selectedDateRange.endDate = null;
1090
+ }
1091
+
1092
+ // Update display element
1093
+ this._updateRangeDisplayElement(start, end);
1094
+
1095
+ // Update hidden inputs
1096
+ if (this._dateInputElement) {
1097
+ let inputValue = formatDate(start, this._config.format, this._config);
1098
+ if (end) {
1099
+ inputValue += `${this._config.rangeSeparator}${formatDate(
1100
+ end,
1101
+ this._config.format,
1102
+ this._config,
1103
+ )}`;
1104
+ }
1105
+ this._dateInputElement.value = inputValue;
1106
+ this._dateInputElement.dispatchEvent(
1107
+ new Event('change', { bubbles: true }),
1108
+ );
1109
+ }
1110
+
1111
+ if (this._startDateInputElement) {
1112
+ this._startDateInputElement.value = formatDate(
1113
+ start,
1114
+ this._config.format,
1115
+ this._config,
1116
+ );
1117
+ this._startDateInputElement.dispatchEvent(
1118
+ new Event('change', { bubbles: true }),
1119
+ );
1120
+ }
1121
+
1122
+ if (this._endDateInputElement && end) {
1123
+ this._endDateInputElement.value = formatDate(
1124
+ end,
1125
+ this._config.format,
1126
+ this._config,
1127
+ );
1128
+ this._endDateInputElement.dispatchEvent(
1129
+ new Event('change', { bubbles: true }),
1130
+ );
1131
+ } else if (this._endDateInputElement) {
1132
+ this._endDateInputElement.value = '';
1133
+ }
1134
+
1135
+ // Dispatch change event
1136
+ this._eventManager.dispatchEvent(KTDatepickerEventName.DATE_CHANGE, {
1137
+ selectedDateRange: state.selectedDateRange,
1138
+ });
1139
+ } else {
1140
+ // Clear selection
1141
+ this._state.getState().selectedDateRange = null;
1142
+
1143
+ // Clear display
1144
+ if (this._displayElement) {
1145
+ const placeholder =
1146
+ this._dateInputElement?.getAttribute('placeholder') ||
1147
+ 'Select date range';
1148
+ this._displayElement.innerHTML = placeholderTemplate(placeholder);
1149
+ }
1150
+
1151
+ // Clear inputs
1152
+ if (this._dateInputElement) {
1153
+ this._dateInputElement.value = '';
1154
+ this._dateInputElement.dispatchEvent(
1155
+ new Event('change', { bubbles: true }),
1156
+ );
1157
+ }
1158
+
1159
+ if (this._startDateInputElement) {
1160
+ this._startDateInputElement.value = '';
1161
+ this._startDateInputElement.dispatchEvent(
1162
+ new Event('change', { bubbles: true }),
1163
+ );
1164
+ }
1165
+
1166
+ if (this._endDateInputElement) {
1167
+ this._endDateInputElement.value = '';
1168
+ this._endDateInputElement.dispatchEvent(
1169
+ new Event('change', { bubbles: true }),
1170
+ );
1171
+ }
1172
+
1173
+ this._eventManager.dispatchEvent(KTDatepickerEventName.DATE_CHANGE, {
1174
+ selectedDateRange: null,
1175
+ });
1176
+ }
1177
+ }
1178
+
1179
+ /**
1180
+ * Set the minimum selectable date
1181
+ *
1182
+ * @param minDate - Minimum date or null to remove constraint
1183
+ */
1184
+ public setMinDate(minDate: Date | null): void {
1185
+ this._config.minDate = minDate;
1186
+
1187
+ // Refresh calendar view to apply new constraints
1188
+ this._eventManager.dispatchEvent(KTDatepickerEventName.UPDATE);
1189
+ }
1190
+
1191
+ /**
1192
+ * Set the maximum selectable date
1193
+ *
1194
+ * @param maxDate - Maximum date or null to remove constraint
1195
+ */
1196
+ public setMaxDate(maxDate: Date | null): void {
1197
+ this._config.maxDate = maxDate;
1198
+
1199
+ // Refresh calendar view to apply new constraints
1200
+ this._eventManager.dispatchEvent(KTDatepickerEventName.UPDATE);
1201
+ }
1202
+
1203
+ /**
1204
+ * Update the datepicker (refresh view)
1205
+ */
1206
+ public update(): void {
1207
+ // Trigger calendar update through events
1208
+ this._eventManager.dispatchEvent(KTDatepickerEventName.UPDATE);
1209
+ }
1210
+
1211
+ /**
1212
+ * Destroy the datepicker instance and clean up
1213
+ */
1214
+ public destroy(): void {
1215
+ // Remove event listeners
1216
+ this._eventManager.removeEventListener(
1217
+ KTDatepickerEventName.DATE_CHANGE,
1218
+ this._handleDateChange.bind(this),
1219
+ );
1220
+
1221
+ if (this._dateInputElement) {
1222
+ this._dateInputElement.removeEventListener(
1223
+ 'change',
1224
+ this._handleInputChange.bind(this),
1225
+ );
1226
+ }
1227
+
1228
+ if (this._displayElement) {
1229
+ this._displayElement.remove();
1230
+ }
1231
+
1232
+ // Remove instance from element
1233
+ this._element.removeAttribute('data-kt-datepicker-initialized');
1234
+ delete (this._element as any).instance;
1235
+
1236
+ // Remove initialized class
1237
+ this._element.classList.remove('relative');
1238
+
1239
+ // Remove from instances map
1240
+ KTDatepicker._instances.delete(this._element);
1241
+ }
1242
+
1243
+ /**
1244
+ * Dispatch a custom event
1245
+ *
1246
+ * @param eventName - Name of the event
1247
+ * @param payload - Optional event payload
1248
+ */
1249
+ protected _dispatchEvent(eventName: string, payload?: any): void {
1250
+ this._eventManager.dispatchEvent(eventName, payload);
1251
+ }
1252
+
1253
+ /**
1254
+ * ========================================================================
1255
+ * Static instances
1256
+ * ========================================================================
1257
+ */
1258
+
1259
+ private static readonly _instances = new Map<HTMLElement, KTDatepicker>();
1260
+
1261
+ /**
1262
+ * Create instances for all datepicker elements on the page
1263
+ */
1264
+ public static createInstances(): void {
1265
+ const elements = document.querySelectorAll<HTMLElement>(
1266
+ '[data-kt-datepicker]',
1267
+ );
1268
+
1269
+ elements.forEach((element) => {
1270
+ if (
1271
+ element.hasAttribute('data-kt-datepicker') &&
1272
+ !element.getAttribute('data-kt-datepicker-initialized')
1273
+ ) {
1274
+ // Create instance
1275
+ const instance = new KTDatepicker(element);
1276
+ this._instances.set(element, instance);
1277
+ }
1278
+ });
1279
+ }
1280
+
1281
+ /**
1282
+ * Initialize all datepickers on the page
1283
+ */
1284
+ public static init(): void {
1285
+ KTDatepicker.createInstances();
1286
+ }
1287
+ }