@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
@@ -0,0 +1,438 @@
1
+ /*
2
+ * time-picker.ts - Time picker renderer for KTDatepicker
3
+ * Provides time picker UI components with increment/decrement controls.
4
+ * Uses unified template system for consistent rendering.
5
+ */
6
+
7
+ import { TimeState } from '../../config/types';
8
+ import { formatTime, validateTime } from '../../utils/time-utils';
9
+ import { createTemplateRenderer } from '../../ui/templates/templates';
10
+ import { KTDatepickerTemplateStrings } from '../../config/types';
11
+
12
+ /**
13
+ * Options for rendering time picker
14
+ */
15
+ export interface TimePickerOptions {
16
+ time: TimeState;
17
+ granularity: 'second' | 'minute' | 'hour';
18
+ format: '12h' | '24h';
19
+ minTime?: string;
20
+ maxTime?: string;
21
+ timeStep?: number;
22
+ disabled?: boolean;
23
+ onChange?: (time: TimeState) => void;
24
+ templates?: KTDatepickerTemplateStrings;
25
+ }
26
+
27
+ /**
28
+ * Render time picker component
29
+ * @param container Container element
30
+ * @param options Time picker options
31
+ * @returns Object with cleanup function and update function
32
+ */
33
+ export function renderTimePicker(container: HTMLElement, options: TimePickerOptions): { cleanup: () => void; update: (newTime: TimeState) => void } {
34
+ const { time, granularity, format, minTime, maxTime, timeStep = 1, disabled = false, onChange, templates } = options;
35
+
36
+ // Initialize template renderer
37
+ const templateRenderer = createTemplateRenderer(templates || {});
38
+
39
+ // Clear container
40
+ container.innerHTML = '';
41
+
42
+ // Current time state (will be updated)
43
+ let currentTime = { ...time };
44
+
45
+ // Store references to updateable elements
46
+ const updateableElements: { [key: string]: HTMLElement } = {};
47
+
48
+ // Create increment/decrement buttons for each time unit
49
+ const timeUnits = getTimeUnits(granularity);
50
+
51
+ // Build time units HTML using templates
52
+ let timeUnitsHtml = '';
53
+ timeUnits.forEach((unit, index) => {
54
+ // Render time unit using template
55
+ const unitHtml = templateRenderer.renderTemplateString({
56
+ templateKey: 'timeUnit',
57
+ data: {
58
+ unitType: unit,
59
+ upButton: templateRenderer.renderTemplateString({
60
+ templateKey: 'timeUpButton',
61
+ data: {
62
+ unitType: unit,
63
+ disabled: disabled ? 'disabled' : ''
64
+ }
65
+ }),
66
+ valueDisplay: templateRenderer.renderTemplateString({
67
+ templateKey: 'timeValue',
68
+ data: {
69
+ value: getTimeUnitValue(currentTime, unit, format)
70
+ }
71
+ }),
72
+ downButton: templateRenderer.renderTemplateString({
73
+ templateKey: 'timeDownButton',
74
+ data: {
75
+ unitType: unit,
76
+ disabled: disabled ? 'disabled' : ''
77
+ }
78
+ })
79
+ }
80
+ });
81
+
82
+ timeUnitsHtml += unitHtml;
83
+
84
+ // Add separator between units (except after last unit)
85
+ if (index < timeUnits.length - 1) {
86
+ timeUnitsHtml += templateRenderer.renderTemplateString({
87
+ templateKey: 'timeSeparator',
88
+ data: { separator: ':' }
89
+ });
90
+ }
91
+ });
92
+
93
+ // Render time controls with units
94
+ const timeControlsHtml = templateRenderer.renderTemplateString({
95
+ templateKey: 'timeControls',
96
+ data: {
97
+ timeUnits: timeUnitsHtml,
98
+ ampmControl: format === '12h' ? templateRenderer.renderTemplateString({
99
+ templateKey: 'ampmControl',
100
+ data: {
101
+ ampmButton: templateRenderer.renderTemplateString({
102
+ templateKey: 'ampmButton',
103
+ data: {
104
+ ampmValue: currentTime.hour >= 12 ? 'PM' : 'AM',
105
+ disabled: disabled ? 'disabled' : ''
106
+ }
107
+ })
108
+ }
109
+ }) : ''
110
+ }
111
+ });
112
+
113
+ // Render time display
114
+ const timeDisplayHtml = templateRenderer.renderTemplateString({
115
+ templateKey: 'timeDisplay',
116
+ data: {
117
+ timeValue: formatTime(currentTime, granularity, format)
118
+ }
119
+ });
120
+
121
+ // Render complete time picker wrapper
122
+ const timePickerHtml = templateRenderer.renderTemplateString({
123
+ templateKey: 'timePickerWrapper',
124
+ data: {
125
+ timeDisplay: timeDisplayHtml,
126
+ timeControls: timeControlsHtml
127
+ }
128
+ });
129
+
130
+ // Insert rendered HTML into container
131
+ container.innerHTML = timePickerHtml;
132
+
133
+ // Get references to elements for event handling
134
+ const timeDisplay = container.querySelector('[data-kt-datepicker-time-display]') as HTMLElement;
135
+
136
+ // Add event listeners to time unit buttons
137
+ timeUnits.forEach((unit) => {
138
+ const upButton = container.querySelector(`[data-kt-datepicker-time-up][aria-label="Increment ${unit}"]`) as HTMLButtonElement;
139
+ const downButton = container.querySelector(`[data-kt-datepicker-time-down][aria-label="Decrement ${unit}"]`) as HTMLButtonElement;
140
+ const valueDisplay = container.querySelector(`[data-kt-datepicker-time-unit="${unit}"] [data-kt-datepicker-time-value]`) as HTMLElement;
141
+
142
+ // Store reference for updates
143
+ updateableElements[`${unit}Value`] = valueDisplay;
144
+
145
+ // Add event listeners with UI update
146
+ upButton.addEventListener('click', () => {
147
+ if (!disabled && onChange) {
148
+ const newTime = incrementTimeUnit(currentTime, unit, timeStep, format);
149
+
150
+ const validation = validateTime(newTime, minTime, maxTime);
151
+
152
+ if (validation.isValid) {
153
+ // Update current time state
154
+ currentTime = newTime;
155
+ // Update UI immediately
156
+ updateTimeDisplay(currentTime, updateableElements, timeDisplay, granularity, format);
157
+ // Call onChange callback
158
+ onChange(currentTime);
159
+ }
160
+ }
161
+ });
162
+
163
+ downButton.addEventListener('click', () => {
164
+ if (!disabled && onChange) {
165
+ const newTime = decrementTimeUnit(currentTime, unit, timeStep, format);
166
+
167
+ const validation = validateTime(newTime, minTime, maxTime);
168
+
169
+ if (validation.isValid) {
170
+ // Update current time state
171
+ currentTime = newTime;
172
+ // Update UI immediately
173
+ updateTimeDisplay(currentTime, updateableElements, timeDisplay, granularity, format);
174
+ // Call onChange callback
175
+ onChange(currentTime);
176
+ }
177
+ }
178
+ });
179
+ });
180
+
181
+ // Add AM/PM toggle for 12-hour format
182
+ if (format === '12h') {
183
+ const ampmButton = container.querySelector('[data-kt-datepicker-ampm-button]') as HTMLButtonElement;
184
+
185
+ ampmButton.addEventListener('click', () => {
186
+ if (!disabled && onChange) {
187
+ const newTime = { ...currentTime };
188
+ if (newTime.hour >= 12) {
189
+ newTime.hour = newTime.hour - 12;
190
+ } else {
191
+ newTime.hour = newTime.hour + 12;
192
+ }
193
+ if (validateTime(newTime, minTime, maxTime).isValid) {
194
+ // Update current time state
195
+ currentTime = newTime;
196
+ // Update UI immediately
197
+ updateTimeDisplay(currentTime, updateableElements, timeDisplay, granularity, format);
198
+ // Update AM/PM button text
199
+ ampmButton.textContent = currentTime.hour >= 12 ? 'PM' : 'AM';
200
+ // Call onChange callback
201
+ onChange(currentTime);
202
+ }
203
+ }
204
+ });
205
+ }
206
+
207
+ // Add keyboard navigation for time picker
208
+ container.addEventListener('keydown', (e) => {
209
+ if (disabled) return;
210
+
211
+ // Handle arrow up/down for time units
212
+ if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
213
+ e.preventDefault();
214
+ e.stopPropagation();
215
+
216
+ // Find the currently focused time unit
217
+ const focusedElement = document.activeElement;
218
+ if (!focusedElement || !container.contains(focusedElement)) return;
219
+
220
+ // Determine which time unit is focused
221
+ let focusedUnit: string | null = null;
222
+ timeUnits.forEach(unit => {
223
+ const unitElement = container.querySelector(`[data-kt-datepicker-time-unit="${unit}"]`);
224
+ if (unitElement && unitElement.contains(focusedElement)) {
225
+ focusedUnit = unit;
226
+ }
227
+ });
228
+
229
+ // If no specific unit is focused, focus the first one
230
+ if (!focusedUnit && timeUnits.length > 0) {
231
+ focusedUnit = timeUnits[0];
232
+ }
233
+
234
+ if (focusedUnit && onChange) {
235
+ let newTime: TimeState;
236
+ if (e.key === 'ArrowUp') {
237
+ newTime = incrementTimeUnit(currentTime, focusedUnit, timeStep, format);
238
+ } else {
239
+ newTime = decrementTimeUnit(currentTime, focusedUnit, timeStep, format);
240
+ }
241
+
242
+ const validation = validateTime(newTime, minTime, maxTime);
243
+ if (validation.isValid) {
244
+ // Update current time state
245
+ currentTime = newTime;
246
+ // Update UI immediately
247
+ updateTimeDisplay(currentTime, updateableElements, timeDisplay, granularity, format);
248
+ // Call onChange callback
249
+ onChange(currentTime);
250
+ }
251
+ }
252
+ }
253
+
254
+ // Handle Tab navigation between time units
255
+ if (e.key === 'Tab') {
256
+ const timeUnitElements = timeUnits.map(unit =>
257
+ container.querySelector(`[data-kt-datepicker-time-unit="${unit}"]`)
258
+ ).filter(Boolean) as HTMLElement[];
259
+
260
+ if (timeUnitElements.length > 0) {
261
+ const currentIndex = timeUnitElements.findIndex(el => el.contains(document.activeElement));
262
+ let nextIndex = currentIndex;
263
+
264
+ if (e.shiftKey) {
265
+ // Shift+Tab: move to previous
266
+ nextIndex = currentIndex > 0 ? currentIndex - 1 : timeUnitElements.length - 1;
267
+ } else {
268
+ // Tab: move to next
269
+ nextIndex = currentIndex < timeUnitElements.length - 1 ? currentIndex + 1 : 0;
270
+ }
271
+
272
+ if (nextIndex >= 0 && nextIndex < timeUnitElements.length) {
273
+ timeUnitElements[nextIndex].focus();
274
+ e.preventDefault();
275
+ }
276
+ }
277
+ }
278
+ });
279
+
280
+ // Make time units focusable
281
+ timeUnits.forEach(unit => {
282
+ const unitElement = container.querySelector(`[data-kt-datepicker-time-unit="${unit}"]`) as HTMLElement;
283
+ if (unitElement) {
284
+ unitElement.tabIndex = 0;
285
+ unitElement.setAttribute('role', 'spinbutton');
286
+ unitElement.setAttribute('aria-label', `${unit} value`);
287
+ }
288
+ });
289
+
290
+ // Update function to sync with external state changes
291
+ const update = (newTime: TimeState) => {
292
+ currentTime = { ...newTime };
293
+ updateTimeDisplay(currentTime, updateableElements, timeDisplay, granularity, format);
294
+
295
+ // Update AM/PM button if it exists
296
+ if (format === '12h') {
297
+ const ampmButton = container.querySelector('.kt-datepicker-time-ampm-button') as HTMLButtonElement;
298
+ if (ampmButton) {
299
+ ampmButton.textContent = currentTime.hour >= 12 ? 'PM' : 'AM';
300
+ }
301
+ }
302
+ };
303
+
304
+ // Return cleanup function and update function
305
+ return {
306
+ cleanup: () => {
307
+ container.innerHTML = '';
308
+ },
309
+ update
310
+ };
311
+ }
312
+
313
+ /**
314
+ * Update time picker display elements with new time values
315
+ * @param time New time state
316
+ * @param updateableElements Object containing references to updateable DOM elements
317
+ * @param timeDisplay Main time display element
318
+ * @param granularity Time granularity
319
+ * @param format Time format
320
+ */
321
+ function updateTimeDisplay(
322
+ time: TimeState,
323
+ updateableElements: { [key: string]: HTMLElement },
324
+ timeDisplay: HTMLElement,
325
+ granularity: 'second' | 'minute' | 'hour',
326
+ format: '12h' | '24h'
327
+ ): void {
328
+ // Update main time display
329
+ const mainDisplayText = formatTime(time, granularity, format);
330
+ timeDisplay.textContent = mainDisplayText;
331
+
332
+ // Update individual time unit displays
333
+ const timeUnits = getTimeUnits(granularity);
334
+
335
+ timeUnits.forEach(unit => {
336
+ const elementKey = `${unit}Value`;
337
+ const element = updateableElements[elementKey];
338
+ if (element) {
339
+ const unitValue = getTimeUnitValue(time, unit, format);
340
+ element.textContent = unitValue;
341
+ }
342
+ });
343
+ }
344
+
345
+ /**
346
+ * Get time units based on granularity
347
+ * @param granularity Time granularity
348
+ * @returns Array of time unit names
349
+ */
350
+ function getTimeUnits(granularity: 'second' | 'minute' | 'hour'): string[] {
351
+ switch (granularity) {
352
+ case 'hour':
353
+ return ['hour'];
354
+ case 'minute':
355
+ return ['hour', 'minute'];
356
+ case 'second':
357
+ return ['hour', 'minute', 'second'];
358
+ default:
359
+ return ['hour', 'minute'];
360
+ }
361
+ }
362
+
363
+ /**
364
+ * Get display value for time unit
365
+ * @param time TimeState object
366
+ * @param unit Time unit
367
+ * @param format Time format
368
+ * @returns Formatted unit value
369
+ */
370
+ function getTimeUnitValue(time: TimeState, unit: string, format: '12h' | '24h'): string {
371
+ switch (unit) {
372
+ case 'hour':
373
+ let hour = time.hour;
374
+ if (format === '12h') {
375
+ hour = hour % 12;
376
+ hour = hour === 0 ? 12 : hour;
377
+ }
378
+ return hour.toString().padStart(2, '0');
379
+ case 'minute':
380
+ return time.minute.toString().padStart(2, '0');
381
+ case 'second':
382
+ return time.second.toString().padStart(2, '0');
383
+ default:
384
+ return '';
385
+ }
386
+ }
387
+
388
+ /**
389
+ * Increment time unit
390
+ * @param time Current time
391
+ * @param unit Time unit to increment
392
+ * @param step Step increment
393
+ * @param format Time format
394
+ * @returns New time state
395
+ */
396
+ function incrementTimeUnit(time: TimeState, unit: string, step: number, format: '12h' | '24h'): TimeState {
397
+ const newTime = { ...time };
398
+
399
+ switch (unit) {
400
+ case 'hour':
401
+ newTime.hour = (newTime.hour + step) % 24;
402
+ break;
403
+ case 'minute':
404
+ newTime.minute = (newTime.minute + step) % 60;
405
+ break;
406
+ case 'second':
407
+ newTime.second = (newTime.second + step) % 60;
408
+ break;
409
+ }
410
+
411
+ return newTime;
412
+ }
413
+
414
+ /**
415
+ * Decrement time unit
416
+ * @param time Current time
417
+ * @param unit Time unit to decrement
418
+ * @param step Step increment
419
+ * @param format Time format
420
+ * @returns New time state
421
+ */
422
+ function decrementTimeUnit(time: TimeState, unit: string, step: number, format: '12h' | '24h'): TimeState {
423
+ const newTime = { ...time };
424
+
425
+ switch (unit) {
426
+ case 'hour':
427
+ newTime.hour = (newTime.hour - step + 24) % 24;
428
+ break;
429
+ case 'minute':
430
+ newTime.minute = (newTime.minute - step + 60) % 60;
431
+ break;
432
+ case 'second':
433
+ newTime.second = (newTime.second - step + 60) % 60;
434
+ break;
435
+ }
436
+
437
+ return newTime;
438
+ }
@@ -0,0 +1,6 @@
1
+ /*
2
+ * templates/index.ts - Template module exports
3
+ * Provides unified template system for KTDatepicker
4
+ */
5
+
6
+ export * from './templates';