@keenthemes/ktui 1.0.28 → 1.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 (288) hide show
  1. package/README.md +27 -0
  2. package/dist/ktui.js +8780 -6199
  3. package/dist/ktui.min.js +1 -1
  4. package/dist/ktui.min.js.map +1 -1
  5. package/dist/styles.css +2744 -1367
  6. package/lib/cjs/components/alert/alert.js +1025 -0
  7. package/lib/cjs/components/alert/alert.js.map +1 -0
  8. package/lib/cjs/components/alert/index.js +20 -0
  9. package/lib/cjs/components/alert/index.js.map +1 -0
  10. package/lib/cjs/components/alert/templates.js +120 -0
  11. package/lib/cjs/components/alert/templates.js.map +1 -0
  12. package/lib/cjs/components/alert/types.js +7 -0
  13. package/lib/cjs/components/alert/types.js.map +1 -0
  14. package/lib/cjs/components/datepicker/config/config.js +42 -0
  15. package/lib/cjs/components/datepicker/config/config.js.map +1 -0
  16. package/lib/cjs/components/datepicker/config/index.js +24 -0
  17. package/lib/cjs/components/datepicker/config/index.js.map +1 -0
  18. package/lib/cjs/components/datepicker/config/interfaces.js +7 -0
  19. package/lib/cjs/components/datepicker/config/interfaces.js.map +1 -0
  20. package/lib/cjs/components/datepicker/config/types.js +7 -0
  21. package/lib/cjs/components/datepicker/config/types.js.map +1 -0
  22. package/lib/cjs/components/datepicker/core/event-manager.js +135 -0
  23. package/lib/cjs/components/datepicker/core/event-manager.js.map +1 -0
  24. package/lib/cjs/components/datepicker/core/focus-manager.js +167 -0
  25. package/lib/cjs/components/datepicker/core/focus-manager.js.map +1 -0
  26. package/lib/cjs/components/datepicker/core/helpers.js +219 -0
  27. package/lib/cjs/components/datepicker/core/helpers.js.map +1 -0
  28. package/lib/cjs/components/datepicker/core/index.js +25 -0
  29. package/lib/cjs/components/datepicker/core/index.js.map +1 -0
  30. package/lib/cjs/components/datepicker/core/unified-state-manager.js +394 -0
  31. package/lib/cjs/components/datepicker/core/unified-state-manager.js.map +1 -0
  32. package/lib/cjs/components/datepicker/datepicker.js +2066 -763
  33. package/lib/cjs/components/datepicker/datepicker.js.map +1 -1
  34. package/lib/cjs/components/datepicker/index.js +19 -8
  35. package/lib/cjs/components/datepicker/index.js.map +1 -1
  36. package/lib/cjs/components/datepicker/ui/index.js +23 -0
  37. package/lib/cjs/components/datepicker/ui/index.js.map +1 -0
  38. package/lib/cjs/components/datepicker/ui/input/dropdown.js +489 -0
  39. package/lib/cjs/components/datepicker/ui/input/dropdown.js.map +1 -0
  40. package/lib/cjs/components/datepicker/ui/input/index.js +23 -0
  41. package/lib/cjs/components/datepicker/ui/input/index.js.map +1 -0
  42. package/lib/cjs/components/datepicker/ui/input/segmented-input.js +640 -0
  43. package/lib/cjs/components/datepicker/ui/input/segmented-input.js.map +1 -0
  44. package/lib/cjs/components/datepicker/ui/renderers/calendar.js +446 -0
  45. package/lib/cjs/components/datepicker/ui/renderers/calendar.js.map +1 -0
  46. package/lib/cjs/components/datepicker/ui/renderers/footer.js +42 -0
  47. package/lib/cjs/components/datepicker/ui/renderers/footer.js.map +1 -0
  48. package/lib/cjs/components/datepicker/ui/renderers/header.js +32 -0
  49. package/lib/cjs/components/datepicker/ui/renderers/header.js.map +1 -0
  50. package/lib/cjs/components/datepicker/ui/renderers/index.js +25 -0
  51. package/lib/cjs/components/datepicker/ui/renderers/index.js.map +1 -0
  52. package/lib/cjs/components/datepicker/ui/renderers/time-picker.js +384 -0
  53. package/lib/cjs/components/datepicker/ui/renderers/time-picker.js.map +1 -0
  54. package/lib/cjs/components/datepicker/ui/templates/index.js +22 -0
  55. package/lib/cjs/components/datepicker/ui/templates/index.js.map +1 -0
  56. package/lib/cjs/components/datepicker/ui/templates/templates.js +253 -0
  57. package/lib/cjs/components/datepicker/ui/templates/templates.js.map +1 -0
  58. package/lib/cjs/components/datepicker/utils/date-formatters.js +88 -0
  59. package/lib/cjs/components/datepicker/utils/date-formatters.js.map +1 -0
  60. package/lib/cjs/components/datepicker/utils/date-utils.js +194 -0
  61. package/lib/cjs/components/datepicker/utils/date-utils.js.map +1 -0
  62. package/lib/cjs/components/datepicker/utils/index.js +24 -0
  63. package/lib/cjs/components/datepicker/utils/index.js.map +1 -0
  64. package/lib/cjs/components/datepicker/utils/time-utils.js +213 -0
  65. package/lib/cjs/components/datepicker/utils/time-utils.js.map +1 -0
  66. package/lib/cjs/index.js +6 -1
  67. package/lib/cjs/index.js.map +1 -1
  68. package/lib/esm/components/alert/alert.js +1022 -0
  69. package/lib/esm/components/alert/alert.js.map +1 -0
  70. package/lib/esm/components/alert/index.js +4 -0
  71. package/lib/esm/components/alert/index.js.map +1 -0
  72. package/lib/esm/components/alert/templates.js +112 -0
  73. package/lib/esm/components/alert/templates.js.map +1 -0
  74. package/lib/esm/components/alert/types.js +6 -0
  75. package/lib/esm/components/alert/types.js.map +1 -0
  76. package/lib/esm/components/datepicker/config/config.js +39 -0
  77. package/lib/esm/components/datepicker/config/config.js.map +1 -0
  78. package/lib/esm/components/datepicker/config/index.js +8 -0
  79. package/lib/esm/components/datepicker/config/index.js.map +1 -0
  80. package/lib/esm/components/datepicker/config/interfaces.js +6 -0
  81. package/lib/esm/components/datepicker/config/interfaces.js.map +1 -0
  82. package/lib/esm/components/datepicker/config/types.js +6 -0
  83. package/lib/esm/components/datepicker/config/types.js.map +1 -0
  84. package/lib/esm/components/datepicker/core/event-manager.js +133 -0
  85. package/lib/esm/components/datepicker/core/event-manager.js.map +1 -0
  86. package/lib/esm/components/datepicker/core/focus-manager.js +164 -0
  87. package/lib/esm/components/datepicker/core/focus-manager.js.map +1 -0
  88. package/lib/esm/components/datepicker/core/helpers.js +211 -0
  89. package/lib/esm/components/datepicker/core/helpers.js.map +1 -0
  90. package/lib/esm/components/datepicker/core/index.js +9 -0
  91. package/lib/esm/components/datepicker/core/index.js.map +1 -0
  92. package/lib/esm/components/datepicker/core/unified-state-manager.js +391 -0
  93. package/lib/esm/components/datepicker/core/unified-state-manager.js.map +1 -0
  94. package/lib/esm/components/datepicker/datepicker.js +2065 -763
  95. package/lib/esm/components/datepicker/datepicker.js.map +1 -1
  96. package/lib/esm/components/datepicker/index.js +6 -8
  97. package/lib/esm/components/datepicker/index.js.map +1 -1
  98. package/lib/esm/components/datepicker/ui/index.js +7 -0
  99. package/lib/esm/components/datepicker/ui/index.js.map +1 -0
  100. package/lib/esm/components/datepicker/ui/input/dropdown.js +486 -0
  101. package/lib/esm/components/datepicker/ui/input/dropdown.js.map +1 -0
  102. package/lib/esm/components/datepicker/ui/input/index.js +7 -0
  103. package/lib/esm/components/datepicker/ui/input/index.js.map +1 -0
  104. package/lib/esm/components/datepicker/ui/input/segmented-input.js +637 -0
  105. package/lib/esm/components/datepicker/ui/input/segmented-input.js.map +1 -0
  106. package/lib/esm/components/datepicker/ui/renderers/calendar.js +443 -0
  107. package/lib/esm/components/datepicker/ui/renderers/calendar.js.map +1 -0
  108. package/lib/esm/components/datepicker/ui/renderers/footer.js +39 -0
  109. package/lib/esm/components/datepicker/ui/renderers/footer.js.map +1 -0
  110. package/lib/esm/components/datepicker/ui/renderers/header.js +29 -0
  111. package/lib/esm/components/datepicker/ui/renderers/header.js.map +1 -0
  112. package/lib/esm/components/datepicker/ui/renderers/index.js +9 -0
  113. package/lib/esm/components/datepicker/ui/renderers/index.js.map +1 -0
  114. package/lib/esm/components/datepicker/ui/renderers/time-picker.js +381 -0
  115. package/lib/esm/components/datepicker/ui/renderers/time-picker.js.map +1 -0
  116. package/lib/esm/components/datepicker/ui/templates/index.js +6 -0
  117. package/lib/esm/components/datepicker/ui/templates/index.js.map +1 -0
  118. package/lib/esm/components/datepicker/ui/templates/templates.js +242 -0
  119. package/lib/esm/components/datepicker/ui/templates/templates.js.map +1 -0
  120. package/lib/esm/components/datepicker/utils/date-formatters.js +83 -0
  121. package/lib/esm/components/datepicker/utils/date-formatters.js.map +1 -0
  122. package/lib/esm/components/datepicker/utils/date-utils.js +184 -0
  123. package/lib/esm/components/datepicker/utils/date-utils.js.map +1 -0
  124. package/lib/esm/components/datepicker/utils/index.js +8 -0
  125. package/lib/esm/components/datepicker/utils/index.js.map +1 -0
  126. package/lib/esm/components/datepicker/utils/time-utils.js +201 -0
  127. package/lib/esm/components/datepicker/utils/time-utils.js.map +1 -0
  128. package/lib/esm/index.js +4 -0
  129. package/lib/esm/index.js.map +1 -1
  130. package/package.json +22 -3
  131. package/src/components/alert/alert.css +429 -188
  132. package/src/components/alert/alert.ts +990 -0
  133. package/src/components/alert/index.ts +4 -0
  134. package/src/components/alert/templates.ts +110 -0
  135. package/src/components/alert/tests/accessibility/aria-roles.test.ts +19 -0
  136. package/src/components/alert/tests/accessibility/focus-management.test.ts +19 -0
  137. package/src/components/alert/tests/accessibility/keyboard-nav.test.ts +22 -0
  138. package/src/components/alert/tests/actions/confirm-cancel.test.ts +122 -0
  139. package/src/components/alert/tests/actions/input-field.test.ts +180 -0
  140. package/src/components/alert/tests/alert.basic.test.ts +126 -0
  141. package/src/components/alert/tests/alert.config.test.ts +75 -0
  142. package/src/components/alert/tests/alert.templates.test.ts +17 -0
  143. package/src/components/alert/tests/config/attribute-config.test.ts +94 -0
  144. package/src/components/alert/tests/config/json-config.test.ts +119 -0
  145. package/src/components/alert/tests/config/merging.test.ts +89 -0
  146. package/src/components/alert/tests/dismissal/auto-dismiss.test.ts +96 -0
  147. package/src/components/alert/tests/dismissal/escape-key-dismiss.test.ts +105 -0
  148. package/src/components/alert/tests/dismissal/manual-dismiss.test.ts +90 -0
  149. package/src/components/alert/tests/dismissal/outside-click-dismiss.test.ts +91 -0
  150. package/src/components/alert/tests/edge-cases/invalid-config.test.ts +19 -0
  151. package/src/components/alert/tests/edge-cases/multiple-alerts.test.ts +19 -0
  152. package/src/components/alert/tests/rendering/custom-content.test.ts +81 -0
  153. package/src/components/alert/tests/rendering/info-alert.test.ts +84 -0
  154. package/src/components/alert/tests/rendering/success-alert.test.ts +100 -0
  155. package/src/components/alert/tests/templates/default-templates.test.ts +16 -0
  156. package/src/components/alert/tests/templates/user-templates.test.ts +16 -0
  157. package/src/components/alert/types.ts +145 -0
  158. package/src/components/datepicker/__tests__/datepicker-events.test.ts +356 -0
  159. package/src/components/datepicker/__tests__/datepicker-init.test.ts +343 -0
  160. package/src/components/datepicker/__tests__/datepicker-integration.test.ts +435 -0
  161. package/src/components/datepicker/__tests__/datepicker-timezone.test.ts +220 -0
  162. package/src/components/datepicker/__tests__/segmented-input-focus.test.ts +380 -0
  163. package/src/components/datepicker/__tests__/selective-state-updates.test.ts +400 -0
  164. package/src/components/datepicker/__tests__/state-manager.test.ts +421 -0
  165. package/src/components/datepicker/__tests__/time-preservation.test.ts +387 -0
  166. package/src/components/datepicker/config/config.ts +40 -0
  167. package/src/components/datepicker/config/index.ts +8 -0
  168. package/src/components/datepicker/config/interfaces.ts +82 -0
  169. package/src/components/datepicker/config/types.ts +188 -0
  170. package/src/components/datepicker/core/event-manager.ts +159 -0
  171. package/src/components/datepicker/core/focus-manager.ts +201 -0
  172. package/src/components/datepicker/core/helpers.ts +231 -0
  173. package/src/components/datepicker/core/index.ts +9 -0
  174. package/src/components/datepicker/core/unified-state-manager.ts +459 -0
  175. package/src/components/datepicker/datepicker.css +429 -1
  176. package/src/components/datepicker/datepicker.ts +2538 -1277
  177. package/src/components/datepicker/index.ts +6 -8
  178. package/src/components/datepicker/ui/index.ts +7 -0
  179. package/src/components/datepicker/ui/input/dropdown.ts +552 -0
  180. package/src/components/datepicker/ui/input/index.ts +7 -0
  181. package/src/components/datepicker/ui/input/segmented-input.ts +638 -0
  182. package/src/components/datepicker/ui/renderers/__tests__/calendar-optimizations.test.ts +611 -0
  183. package/src/components/datepicker/ui/renderers/calendar.ts +530 -0
  184. package/src/components/datepicker/ui/renderers/footer.ts +43 -0
  185. package/src/components/datepicker/ui/renderers/header.ts +33 -0
  186. package/src/components/datepicker/ui/renderers/index.ts +9 -0
  187. package/src/components/datepicker/ui/renderers/time-picker.ts +438 -0
  188. package/src/components/datepicker/ui/templates/index.ts +6 -0
  189. package/src/components/datepicker/ui/templates/templates.ts +306 -0
  190. package/src/components/datepicker/utils/__tests__/date-formatters.test.ts +160 -0
  191. package/src/components/datepicker/utils/__tests__/date-utils-keys.test.ts +86 -0
  192. package/src/components/datepicker/utils/__tests__/date-utils-timezone.test.ts +215 -0
  193. package/src/components/datepicker/utils/date-formatters.ts +85 -0
  194. package/src/components/datepicker/utils/date-utils.ts +172 -0
  195. package/src/components/datepicker/utils/index.ts +8 -0
  196. package/src/components/datepicker/utils/time-utils.ts +221 -0
  197. package/src/index.ts +7 -1
  198. package/CONTRIBUTING.md +0 -101
  199. package/examples/datatable/checkbox-events-test.html +0 -400
  200. package/examples/datatable/credentials-test.html +0 -423
  201. package/examples/datatable/remote-checkbox-test.html +0 -365
  202. package/examples/datatable/sorting-test.html +0 -258
  203. package/examples/image-input/file-upload-example.html +0 -189
  204. package/examples/modal/persistent.html +0 -205
  205. package/examples/modal/remote-select-dropdown.html +0 -166
  206. package/examples/modal/select-dropdown-container.html +0 -129
  207. package/examples/select/avatar.html +0 -47
  208. package/examples/select/basic-usage.html +0 -39
  209. package/examples/select/country.html +0 -43
  210. package/examples/select/dark-mode.html +0 -93
  211. package/examples/select/description.html +0 -53
  212. package/examples/select/disable-option.html +0 -37
  213. package/examples/select/disable-select.html +0 -35
  214. package/examples/select/dropdowncontainer.html +0 -111
  215. package/examples/select/dynamic-methods.html +0 -273
  216. package/examples/select/formdata-remote.html +0 -161
  217. package/examples/select/global-config.html +0 -81
  218. package/examples/select/icon-multiple.html +0 -50
  219. package/examples/select/icon.html +0 -48
  220. package/examples/select/max-selection.html +0 -38
  221. package/examples/select/modal-container.html +0 -128
  222. package/examples/select/modal-positioning-test.html +0 -338
  223. package/examples/select/modal.html +0 -80
  224. package/examples/select/multiple.html +0 -40
  225. package/examples/select/native-selected.html +0 -64
  226. package/examples/select/placeholder.html +0 -40
  227. package/examples/select/remote-data-preselected.html +0 -283
  228. package/examples/select/remote-data.html +0 -38
  229. package/examples/select/search.html +0 -57
  230. package/examples/select/sizes.html +0 -94
  231. package/examples/select/tags-enhanced.html +0 -86
  232. package/examples/select/tags-icons.html +0 -57
  233. package/examples/select/template-customization.html +0 -61
  234. package/examples/sticky/README.md +0 -158
  235. package/examples/sticky/debug-sticky.html +0 -144
  236. package/examples/sticky/test-runner.html +0 -175
  237. package/examples/sticky/test-sticky-logic.js +0 -369
  238. package/examples/sticky/test-sticky-positioning.html +0 -386
  239. package/examples/toast/example.html +0 -479
  240. package/lib/cjs/components/datepicker/calendar.js +0 -1061
  241. package/lib/cjs/components/datepicker/calendar.js.map +0 -1
  242. package/lib/cjs/components/datepicker/config.js +0 -332
  243. package/lib/cjs/components/datepicker/config.js.map +0 -1
  244. package/lib/cjs/components/datepicker/dropdown.js +0 -635
  245. package/lib/cjs/components/datepicker/dropdown.js.map +0 -1
  246. package/lib/cjs/components/datepicker/events.js +0 -129
  247. package/lib/cjs/components/datepicker/events.js.map +0 -1
  248. package/lib/cjs/components/datepicker/keyboard.js +0 -536
  249. package/lib/cjs/components/datepicker/keyboard.js.map +0 -1
  250. package/lib/cjs/components/datepicker/locales.js +0 -78
  251. package/lib/cjs/components/datepicker/locales.js.map +0 -1
  252. package/lib/cjs/components/datepicker/templates.js +0 -403
  253. package/lib/cjs/components/datepicker/templates.js.map +0 -1
  254. package/lib/cjs/components/datepicker/types.js +0 -23
  255. package/lib/cjs/components/datepicker/types.js.map +0 -1
  256. package/lib/cjs/components/datepicker/utils.js +0 -524
  257. package/lib/cjs/components/datepicker/utils.js.map +0 -1
  258. package/lib/esm/components/datepicker/calendar.js +0 -1058
  259. package/lib/esm/components/datepicker/calendar.js.map +0 -1
  260. package/lib/esm/components/datepicker/config.js +0 -329
  261. package/lib/esm/components/datepicker/config.js.map +0 -1
  262. package/lib/esm/components/datepicker/dropdown.js +0 -632
  263. package/lib/esm/components/datepicker/dropdown.js.map +0 -1
  264. package/lib/esm/components/datepicker/events.js +0 -126
  265. package/lib/esm/components/datepicker/events.js.map +0 -1
  266. package/lib/esm/components/datepicker/keyboard.js +0 -533
  267. package/lib/esm/components/datepicker/keyboard.js.map +0 -1
  268. package/lib/esm/components/datepicker/locales.js +0 -74
  269. package/lib/esm/components/datepicker/locales.js.map +0 -1
  270. package/lib/esm/components/datepicker/templates.js +0 -390
  271. package/lib/esm/components/datepicker/templates.js.map +0 -1
  272. package/lib/esm/components/datepicker/types.js +0 -20
  273. package/lib/esm/components/datepicker/types.js.map +0 -1
  274. package/lib/esm/components/datepicker/utils.js +0 -508
  275. package/lib/esm/components/datepicker/utils.js.map +0 -1
  276. package/prettier.config.js +0 -9
  277. package/src/components/datepicker/calendar.ts +0 -1397
  278. package/src/components/datepicker/config.ts +0 -368
  279. package/src/components/datepicker/dropdown.ts +0 -757
  280. package/src/components/datepicker/events.ts +0 -149
  281. package/src/components/datepicker/keyboard.ts +0 -646
  282. package/src/components/datepicker/locales.ts +0 -80
  283. package/src/components/datepicker/templates.ts +0 -792
  284. package/src/components/datepicker/types.ts +0 -154
  285. package/src/components/datepicker/utils.ts +0 -631
  286. package/src/components/select/variants.css +0 -4
  287. package/tsconfig.json +0 -17
  288. package/webpack.config.js +0 -118
@@ -1,10 +1,8 @@
1
- /**
2
- * KTUI - Free & Open-Source Tailwind UI Components by Keenthemes
3
- * Copyright 2025 by Keenthemes Inc
4
- */
1
+ import { KTDatepicker, initDatepickers } from './datepicker';
5
2
 
6
- import { KTDatepicker } from './datepicker';
7
- import * as DatepickerTypes from './types';
3
+ // Attach static init method to KTDatepicker
4
+ (KTDatepicker as any).init = initDatepickers;
8
5
 
9
- export { KTDatepicker, DatepickerTypes };
10
- export default KTDatepicker;
6
+ export { KTDatepicker };
7
+ export * from './ui/templates/templates';
8
+ export * from './config/types';
@@ -0,0 +1,7 @@
1
+ /*
2
+ * ui/index.ts - UI module exports
3
+ * Provides all UI components for KTDatepicker
4
+ */
5
+
6
+ export * from './renderers';
7
+ export * from './input';
@@ -0,0 +1,552 @@
1
+ /*
2
+ * dropdown.ts - Datepicker dropdown management
3
+ * Provides dropdown functionality for KTDatepicker following select component patterns.
4
+ * Handles positioning, transitions, and event management.
5
+ */
6
+
7
+ import {
8
+ Instance as PopperInstance,
9
+ createPopper,
10
+ Placement,
11
+ } from '@popperjs/core';
12
+ import KTDom from '../../../../helpers/dom';
13
+ import KTData from '../../../../helpers/data';
14
+ import KTComponent from '../../../component';
15
+ import { KTDatepickerConfig } from '../../config/types';
16
+ import { EventManager } from '../../core/event-manager';
17
+ import { StateObserver, KTDatepickerUnifiedStateManager } from '../../core/unified-state-manager';
18
+ import { KTDatepickerState } from '../../config/types';
19
+
20
+ /**
21
+ * KTDatepickerDropdown
22
+ *
23
+ * A specialized dropdown implementation for the KTDatepicker component.
24
+ * This module handles the dropdown functionality for the datepicker component,
25
+ * including positioning and showing/hiding.
26
+ */
27
+ export class KTDatepickerDropdown extends KTComponent implements StateObserver {
28
+ protected override readonly _name: string = 'datepicker-dropdown';
29
+ protected override readonly _config: KTDatepickerConfig;
30
+
31
+ // DOM Elements
32
+ protected _element: HTMLElement;
33
+ private _toggleElement: HTMLElement;
34
+ private _dropdownElement: HTMLElement;
35
+
36
+ // State (will be managed by unified state manager)
37
+ private _isOpen: boolean = false;
38
+ private _isTransitioning: boolean = false;
39
+ private _popperInstance: PopperInstance | null = null;
40
+ private _eventManager: EventManager;
41
+
42
+ // Unified state manager reference
43
+ private _unifiedStateManager: KTDatepickerUnifiedStateManager | null = null;
44
+
45
+ /**
46
+ * Constructor
47
+ * @param element The parent element (datepicker wrapper)
48
+ * @param toggleElement The element that triggers the dropdown
49
+ * @param dropdownElement The dropdown content element
50
+ * @param config The configuration options
51
+ */
52
+ constructor(
53
+ element: HTMLElement,
54
+ toggleElement: HTMLElement,
55
+ dropdownElement: HTMLElement,
56
+ config: KTDatepickerConfig,
57
+ ) {
58
+ super();
59
+
60
+ this._element = element;
61
+ this._toggleElement = toggleElement;
62
+ this._dropdownElement = dropdownElement;
63
+ this._config = config;
64
+
65
+ const container = this._resolveDropdownContainer();
66
+ if (container) {
67
+ if (container !== this._dropdownElement.parentElement) {
68
+ container.appendChild(this._dropdownElement);
69
+ }
70
+ }
71
+
72
+ this._eventManager = new EventManager();
73
+ this._setupEventListeners();
74
+ }
75
+
76
+ /**
77
+ * Set up event listeners for the dropdown
78
+ */
79
+ private _setupEventListeners(): void {
80
+ // Event listeners are managed by the main datepicker class
81
+ }
82
+
83
+ /**
84
+ * StateObserver implementation
85
+ */
86
+ public onStateChange(newState: KTDatepickerState, oldState: KTDatepickerState): void {
87
+ // React to dropdown state changes from unified state manager
88
+ if (newState.dropdownState.isOpen !== oldState.dropdownState.isOpen) {
89
+ if (newState.dropdownState.isOpen) {
90
+ this._handleOpenFromState();
91
+ } else {
92
+ this._handleCloseFromState();
93
+ }
94
+ }
95
+
96
+ if (newState.dropdownState.isTransitioning !== oldState.dropdownState.isTransitioning) {
97
+ this._isTransitioning = newState.dropdownState.isTransitioning;
98
+ }
99
+ }
100
+
101
+ public getUpdatePriority(): number {
102
+ return 10; // Medium priority for dropdown updates
103
+ }
104
+
105
+ /**
106
+ * Set unified state manager reference
107
+ */
108
+ public setUnifiedStateManager(stateManager: KTDatepickerUnifiedStateManager): void {
109
+ this._unifiedStateManager = stateManager;
110
+ }
111
+
112
+ /**
113
+ * Handle open state change from unified state manager
114
+ */
115
+ private _handleOpenFromState(): void {
116
+ this._isOpen = true;
117
+ this._performOpenTransition();
118
+ }
119
+
120
+ /**
121
+ * Handle close state change from unified state manager
122
+ */
123
+ private _handleCloseFromState(): void {
124
+ this._performCloseTransition();
125
+ }
126
+
127
+ /**
128
+ * Perform the actual open transition
129
+ */
130
+ private _performOpenTransition(): void {
131
+ if (this._isTransitioning) return;
132
+
133
+ // Begin opening transition
134
+ this._isTransitioning = true;
135
+
136
+ // Set initial styles
137
+ this._dropdownElement.classList.remove('hidden');
138
+ this._dropdownElement.style.opacity = '0';
139
+
140
+ // Set dropdown width
141
+ this._setDropdownWidth();
142
+
143
+ // Reflow
144
+ KTDom.reflow(this._dropdownElement);
145
+
146
+ // Apply z-index
147
+ let zIndexToApply: number | null = null;
148
+
149
+ if (this._config.dropdownZindex) {
150
+ zIndexToApply = this._config.dropdownZindex;
151
+ }
152
+
153
+ // Consider the dropdown's current z-index if it's already set and higher
154
+ const currentDropdownZIndexStr = KTDom.getCssProp(this._dropdownElement, 'z-index');
155
+ if (currentDropdownZIndexStr && currentDropdownZIndexStr !== 'auto') {
156
+ const currentDropdownZIndex = parseInt(currentDropdownZIndexStr);
157
+ if (!isNaN(currentDropdownZIndex) && currentDropdownZIndex > (zIndexToApply || 0)) {
158
+ zIndexToApply = currentDropdownZIndex;
159
+ }
160
+ }
161
+
162
+ // Ensure dropdown is above elements within its original toggle's parent context
163
+ const toggleParentContextZindex = KTDom.getHighestZindex(this._element);
164
+ if (toggleParentContextZindex !== null && toggleParentContextZindex >= (zIndexToApply || 0)) {
165
+ zIndexToApply = toggleParentContextZindex + 1;
166
+ }
167
+
168
+ if (zIndexToApply !== null) {
169
+ this._dropdownElement.style.zIndex = zIndexToApply.toString();
170
+ }
171
+
172
+ // Initialize popper
173
+ this._initPopper();
174
+
175
+ // Add active classes for visual state
176
+ this._dropdownElement.classList.add('open');
177
+ this._toggleElement.classList.add('active');
178
+
179
+ // Start transition
180
+ this._dropdownElement.style.opacity = '1';
181
+
182
+ // Handle transition end
183
+ KTDom.transitionEnd(this._dropdownElement, () => {
184
+ this._isTransitioning = false;
185
+
186
+ // Notify unified state manager that transition is complete
187
+ if (this._unifiedStateManager) {
188
+ this._unifiedStateManager.setDropdownTransitioning(false, 'dropdown-transition-complete');
189
+ }
190
+ });
191
+ }
192
+
193
+ /**
194
+ * Perform the actual close transition
195
+ */
196
+ private _performCloseTransition(): void {
197
+ if (this._isTransitioning) return;
198
+
199
+ this._isTransitioning = true;
200
+ this._dropdownElement.style.opacity = '0';
201
+
202
+ let transitionComplete = false;
203
+ const fallbackTimer = setTimeout(() => {
204
+ if (!transitionComplete) {
205
+ transitionComplete = true;
206
+ this._completeCloseTransition();
207
+ }
208
+ }, 300); // Fallback timeout
209
+
210
+ const completeTransition = () => {
211
+ if (!transitionComplete) {
212
+ transitionComplete = true;
213
+ clearTimeout(fallbackTimer);
214
+ this._completeCloseTransition();
215
+ }
216
+ };
217
+
218
+ KTDom.transitionEnd(this._dropdownElement, completeTransition);
219
+ }
220
+
221
+ /**
222
+ * Complete the close transition
223
+ */
224
+ private _completeCloseTransition(): void {
225
+ this._isTransitioning = false;
226
+ this._isOpen = false;
227
+
228
+ // Remove active classes
229
+ this._dropdownElement.classList.remove('open');
230
+ this._toggleElement.classList.remove('active');
231
+
232
+ // Hide dropdown
233
+ this._dropdownElement.classList.add('hidden');
234
+
235
+ // Clean up popper
236
+ this._destroyPopper();
237
+
238
+ // Notify unified state manager that transition is complete
239
+ if (this._unifiedStateManager) {
240
+ this._unifiedStateManager.setDropdownTransitioning(false, 'dropdown-transition-complete');
241
+ }
242
+ }
243
+
244
+ /**
245
+ * Set dropdown width to match input wrapper element (matching ktselect behavior)
246
+ * Dynamically calculates width based on visibleMonths for multi-month view
247
+ */
248
+ private _setDropdownWidth(): void {
249
+ if (!this._dropdownElement || !this._element) return;
250
+
251
+ // Find the input wrapper element to match its width
252
+ const inputWrapper = this._element.querySelector('[data-kt-datepicker-input-wrapper]') as HTMLElement;
253
+ if (!inputWrapper) return;
254
+
255
+ // Get visible months count
256
+ const visibleMonths = this._config.visibleMonths ?? 1;
257
+
258
+ // Check if width is configured
259
+ if (this._config.dropdownWidth) {
260
+ // If custom width is set, use that
261
+ if (this._config.dropdownWidth === 'auto') {
262
+ // Try to measure the actual content width first (if already rendered)
263
+ const multiMonthContainer = this._dropdownElement.querySelector('[data-kt-datepicker-multimonth-container]') as HTMLElement;
264
+
265
+ if (multiMonthContainer && visibleMonths > 1) {
266
+ // Content is already rendered, measure it
267
+ // Force a reflow to ensure accurate measurement
268
+ KTDom.reflow(multiMonthContainer);
269
+
270
+ // Measure content width including gaps
271
+ const contentWidth = multiMonthContainer.scrollWidth;
272
+
273
+ // Add dropdown padding (px-3 = 12px on each side = 24px total)
274
+ const padding = 24;
275
+ const totalWidth = contentWidth + padding;
276
+
277
+ this._dropdownElement.style.width = `${totalWidth}px`;
278
+ this._dropdownElement.style.minWidth = `${totalWidth}px`;
279
+ } else if (visibleMonths > 1) {
280
+ // Content not yet rendered, calculate expected width
281
+ // Base month width: 20rem (320px) per month
282
+ // Gap between months: 1rem (16px) per gap (gap-4)
283
+ // Padding: 0.75rem (12px) on each side = 1.5rem (24px) total
284
+ const monthWidth = 320; // 20rem = 320px
285
+ const gapWidth = 16; // 1rem = 16px (gap-4)
286
+ const paddingWidth = 24; // 1.5rem = 24px (px-3 on each side)
287
+
288
+ // Calculate total width: (n months * 320px) + ((n-1) gaps * 16px) + padding
289
+ const totalWidth = (visibleMonths * monthWidth) + ((visibleMonths - 1) * gapWidth) + paddingWidth;
290
+
291
+ this._dropdownElement.style.width = `${totalWidth}px`;
292
+ this._dropdownElement.style.minWidth = `${totalWidth}px`;
293
+ } else {
294
+ // Single month: use auto (CSS default applies)
295
+ this._dropdownElement.style.width = 'auto';
296
+ this._dropdownElement.style.minWidth = 'auto';
297
+ }
298
+ } else if (typeof this._config.dropdownWidth === 'string') {
299
+ this._dropdownElement.style.width = this._config.dropdownWidth;
300
+ // Clear min-width when custom width is set
301
+ this._dropdownElement.style.minWidth = '';
302
+ }
303
+ } else {
304
+ // Otherwise, match input wrapper width for a cleaner appearance (like ktselect)
305
+ const inputWrapperWidth = inputWrapper.offsetWidth;
306
+ this._dropdownElement.style.width = `${inputWrapperWidth}px`;
307
+ // Clear min-width to ensure input wrapper width takes precedence
308
+ this._dropdownElement.style.minWidth = '';
309
+ }
310
+ }
311
+
312
+ /**
313
+ * Detect if the datepicker is inside a modal container
314
+ * @returns The modal element if found, null otherwise
315
+ */
316
+ private _getModalContainer(): HTMLElement | null {
317
+ return this._element.closest(
318
+ '[data-kt-modal], .kt-modal, .kt-modal-center',
319
+ ) as HTMLElement | null;
320
+ }
321
+
322
+ /**
323
+ * Get the appropriate boundary element for Popper positioning
324
+ * For centered modals, use .kt-modal-content to avoid transform calculation issues
325
+ * @returns The boundary element, or null if no modal found
326
+ */
327
+ private _getModalBoundary(): HTMLElement | null {
328
+ const modalParent = this._getModalContainer();
329
+ if (!modalParent) {
330
+ return null;
331
+ }
332
+
333
+ // For centered modals, use .kt-modal-content as boundary to avoid transform issues
334
+ if (modalParent.classList.contains('kt-modal-center')) {
335
+ const modalContent = modalParent.querySelector(
336
+ '.kt-modal-content',
337
+ ) as HTMLElement | null;
338
+ return modalContent || modalParent;
339
+ }
340
+
341
+ // For non-centered modals, use the modal element itself
342
+ return modalParent;
343
+ }
344
+
345
+ /**
346
+ * Get the appropriate positioning strategy based on context
347
+ * @returns 'fixed' if inside non-centered modal, 'absolute' for centered modals or no modal
348
+ */
349
+ private _getPositioningStrategy(): 'fixed' | 'absolute' {
350
+ // Check if config explicitly sets strategy
351
+ if (this._config.dropdownStrategy) {
352
+ return this._config.dropdownStrategy as 'fixed' | 'absolute';
353
+ }
354
+
355
+ // For centered modals, use absolute positioning to avoid transform calculation issues
356
+ // For non-centered modals, use fixed positioning
357
+ const modalParent = this._getModalContainer();
358
+ if (modalParent && modalParent.classList.contains('kt-modal-center')) {
359
+ return 'absolute';
360
+ }
361
+
362
+ // Use fixed positioning for non-centered modals
363
+ return modalParent ? 'fixed' : 'absolute';
364
+ }
365
+
366
+ /**
367
+ * Get the reference element for Popper positioning (calendar button/icon)
368
+ */
369
+ private _getPopperReferenceElement(): HTMLElement {
370
+ // Use calendar button (toggle element) for positioning - dropdown sticks under the icon
371
+ return this._toggleElement;
372
+ }
373
+
374
+ /**
375
+ * Initialize Popper.js for positioning
376
+ */
377
+ private _initPopper(): void {
378
+ if (this._popperInstance) {
379
+ this._popperInstance.destroy();
380
+ }
381
+
382
+ // Default offset - matching ktselect
383
+ const offsetValue = this._config.dropdownOffset || '0, 5';
384
+
385
+ // Get configuration options
386
+ const placement = (this._config.dropdownPlacement as Placement) || 'bottom-start';
387
+ const strategy = this._getPositioningStrategy();
388
+ const preventOverflow = this._config.dropdownPreventOverflow !== false;
389
+ const flip = this._config.dropdownFlip !== false;
390
+
391
+ // Get appropriate boundary element for modal context
392
+ const boundary = this._getModalBoundary() || this._config.dropdownBoundary || 'clippingParents';
393
+
394
+ // Get reference element for positioning (input wrapper, not the calendar button)
395
+ const referenceElement = this._getPopperReferenceElement();
396
+
397
+ // Create new popper instance
398
+ this._popperInstance = createPopper(
399
+ referenceElement,
400
+ this._dropdownElement,
401
+ {
402
+ placement: placement,
403
+ strategy: strategy,
404
+ modifiers: [
405
+ {
406
+ name: 'offset',
407
+ options: {
408
+ offset: this._parseOffset(offsetValue),
409
+ },
410
+ },
411
+ {
412
+ name: 'preventOverflow',
413
+ options: {
414
+ boundary: boundary,
415
+ altAxis: preventOverflow,
416
+ },
417
+ },
418
+ {
419
+ name: 'flip',
420
+ options: {
421
+ enabled: flip,
422
+ fallbackPlacements: ['top-start', 'bottom-end', 'top-end'],
423
+ },
424
+ },
425
+ {
426
+ name: 'sameWidth',
427
+ enabled: !this._config.dropdownWidth, // Enable when dropdownWidth is null/undefined (matching ktselect)
428
+ phase: 'beforeWrite',
429
+ requires: ['computeStyles'],
430
+ fn: ({ state }) => {
431
+ // Use input wrapper width instead of toggle element width
432
+ const inputWrapper = this._element.querySelector('[data-kt-datepicker-input-wrapper]') as HTMLElement;
433
+ if (inputWrapper) {
434
+ state.styles.popper.width = `${inputWrapper.offsetWidth}px`;
435
+ } else {
436
+ // Fallback to reference width if input wrapper not found
437
+ state.styles.popper.width = `${state.rects.reference.width}px`;
438
+ }
439
+ },
440
+ effect: ({ state }) => {
441
+ // Use input wrapper width instead of toggle element width
442
+ const inputWrapper = this._element.querySelector('[data-kt-datepicker-input-wrapper]') as HTMLElement;
443
+ if (inputWrapper && 'offsetWidth' in inputWrapper) {
444
+ state.elements.popper.style.width = `${inputWrapper.offsetWidth}px`;
445
+ } else {
446
+ // Fallback to reference width if input wrapper not found
447
+ const reference = state.elements.reference as HTMLElement;
448
+ if (reference && 'offsetWidth' in reference) {
449
+ state.elements.popper.style.width = `${reference.offsetWidth}px`;
450
+ }
451
+ }
452
+ },
453
+ },
454
+ ],
455
+ },
456
+ );
457
+ }
458
+
459
+ /**
460
+ * Parse offset string to array
461
+ */
462
+ private _parseOffset(offset: string): number[] {
463
+ return offset.split(',').map((val) => parseInt(val.trim(), 10));
464
+ }
465
+
466
+ /**
467
+ * Destroy Popper instance
468
+ */
469
+ private _destroyPopper(): void {
470
+ if (this._popperInstance) {
471
+ this._popperInstance.destroy();
472
+ this._popperInstance = null;
473
+ }
474
+ }
475
+
476
+ /**
477
+ * Update dropdown position
478
+ */
479
+ public updatePosition(): void {
480
+ if (this._popperInstance) {
481
+ this._popperInstance.update();
482
+ }
483
+ }
484
+
485
+ /**
486
+ * Update dropdown width (useful after content is rendered)
487
+ */
488
+ public updateWidth(): void {
489
+ this._setDropdownWidth();
490
+ // Also update popper position after width change
491
+ if (this._popperInstance) {
492
+ this._popperInstance.update();
493
+ }
494
+ }
495
+
496
+ /**
497
+ * Open the dropdown (legacy method - now handled by observer pattern)
498
+ */
499
+ public open(): void {
500
+ // This method is now deprecated - use unified state manager instead
501
+ if (this._unifiedStateManager) {
502
+ this._unifiedStateManager.setDropdownOpen(true, 'legacy-open-method');
503
+ }
504
+ }
505
+
506
+ /**
507
+ * Close the dropdown (legacy method - now handled by observer pattern)
508
+ */
509
+ public close(): void {
510
+ // This method is now deprecated - use unified state manager instead
511
+ if (this._unifiedStateManager) {
512
+ this._unifiedStateManager.setDropdownOpen(false, 'legacy-close-method');
513
+ }
514
+ }
515
+
516
+ /**
517
+ * Check if dropdown is open
518
+ */
519
+ public isOpen(): boolean {
520
+ return this._isOpen;
521
+ }
522
+
523
+ /**
524
+ * Dispose of the dropdown
525
+ */
526
+ public override dispose(): void {
527
+ // Clean up event listeners
528
+ this._eventManager.removeAllListeners(document as unknown as HTMLElement);
529
+ this._destroyPopper();
530
+
531
+ // Remove dropdown from DOM
532
+ if (this._dropdownElement && this._dropdownElement.parentElement) {
533
+ this._dropdownElement.parentElement.removeChild(this._dropdownElement);
534
+ }
535
+ }
536
+
537
+ /**
538
+ * Resolve the container for the dropdown
539
+ */
540
+ private _resolveDropdownContainer(): HTMLElement | null {
541
+ // Check if dropdown should be rendered in a specific container
542
+ if (this._config.dropdownContainer) {
543
+ const container = document.querySelector(this._config.dropdownContainer);
544
+ if (container instanceof HTMLElement) {
545
+ return container;
546
+ }
547
+ }
548
+
549
+ // Default to body for better positioning
550
+ return document.body;
551
+ }
552
+ }
@@ -0,0 +1,7 @@
1
+ /*
2
+ * ui/input/index.ts - Input module exports
3
+ * Provides input-related components for KTDatepicker
4
+ */
5
+
6
+ export * from './segmented-input';
7
+ export * from './dropdown';