@keenthemes/ktui 1.1.0 → 1.1.2

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 (258) hide show
  1. package/README.md +0 -27
  2. package/dist/ktui.js +5269 -12550
  3. package/dist/ktui.min.js +1 -1
  4. package/dist/ktui.min.js.map +1 -1
  5. package/dist/styles.css +1133 -2706
  6. package/lib/cjs/components/datatable/__tests__/pagination-reset.test.js +596 -0
  7. package/lib/cjs/components/datatable/__tests__/pagination-reset.test.js.map +1 -0
  8. package/lib/cjs/components/datatable/__tests__/race-conditions.test.js +548 -0
  9. package/lib/cjs/components/datatable/__tests__/race-conditions.test.js.map +1 -0
  10. package/lib/cjs/components/datatable/__tests__/setup.js +63 -0
  11. package/lib/cjs/components/datatable/__tests__/setup.js.map +1 -0
  12. package/lib/cjs/components/datatable/datatable.js +92 -30
  13. package/lib/cjs/components/datatable/datatable.js.map +1 -1
  14. package/lib/cjs/components/select/combobox.js +0 -2
  15. package/lib/cjs/components/select/combobox.js.map +1 -1
  16. package/lib/cjs/components/select/config.js +4 -1
  17. package/lib/cjs/components/select/config.js.map +1 -1
  18. package/lib/cjs/components/select/dropdown.js +0 -16
  19. package/lib/cjs/components/select/dropdown.js.map +1 -1
  20. package/lib/cjs/components/select/remote.js +0 -40
  21. package/lib/cjs/components/select/remote.js.map +1 -1
  22. package/lib/cjs/components/select/search.js +80 -19
  23. package/lib/cjs/components/select/search.js.map +1 -1
  24. package/lib/cjs/components/select/select.js +98 -110
  25. package/lib/cjs/components/select/select.js.map +1 -1
  26. package/lib/cjs/components/select/tags.js +0 -2
  27. package/lib/cjs/components/select/tags.js.map +1 -1
  28. package/lib/cjs/index.js +1 -10
  29. package/lib/cjs/index.js.map +1 -1
  30. package/lib/esm/components/datatable/__tests__/pagination-reset.test.js +594 -0
  31. package/lib/esm/components/datatable/__tests__/pagination-reset.test.js.map +1 -0
  32. package/lib/esm/components/datatable/__tests__/race-conditions.test.js +546 -0
  33. package/lib/esm/components/datatable/__tests__/race-conditions.test.js.map +1 -0
  34. package/lib/esm/components/datatable/__tests__/setup.js +58 -0
  35. package/lib/esm/components/datatable/__tests__/setup.js.map +1 -0
  36. package/lib/esm/components/datatable/datatable.js +92 -30
  37. package/lib/esm/components/datatable/datatable.js.map +1 -1
  38. package/lib/esm/components/select/combobox.js +0 -2
  39. package/lib/esm/components/select/combobox.js.map +1 -1
  40. package/lib/esm/components/select/config.js +4 -1
  41. package/lib/esm/components/select/config.js.map +1 -1
  42. package/lib/esm/components/select/dropdown.js +0 -16
  43. package/lib/esm/components/select/dropdown.js.map +1 -1
  44. package/lib/esm/components/select/remote.js +0 -40
  45. package/lib/esm/components/select/remote.js.map +1 -1
  46. package/lib/esm/components/select/search.js +80 -19
  47. package/lib/esm/components/select/search.js.map +1 -1
  48. package/lib/esm/components/select/select.js +98 -110
  49. package/lib/esm/components/select/select.js.map +1 -1
  50. package/lib/esm/components/select/tags.js +0 -2
  51. package/lib/esm/components/select/tags.js.map +1 -1
  52. package/lib/esm/index.js +0 -7
  53. package/lib/esm/index.js.map +1 -1
  54. package/package.json +7 -9
  55. package/src/components/alert/alert.css +188 -429
  56. package/src/components/datatable/__tests__/pagination-reset.test.ts +657 -0
  57. package/src/components/datatable/__tests__/race-conditions.test.ts +455 -0
  58. package/src/components/datatable/__tests__/setup.ts +67 -0
  59. package/src/components/datatable/datatable.ts +66 -11
  60. package/src/components/input/input.css +0 -1
  61. package/src/components/select/__tests__/ux-behaviors.test.ts +619 -0
  62. package/src/components/select/combobox.ts +0 -1
  63. package/src/components/select/config.ts +7 -1
  64. package/src/components/select/dropdown.ts +0 -24
  65. package/src/components/select/remote.ts +0 -49
  66. package/src/components/select/search.ts +85 -21
  67. package/src/components/select/select.css +0 -1
  68. package/src/components/select/select.ts +118 -149
  69. package/src/components/select/tags.ts +0 -1
  70. package/src/components/select/variants.css +4 -0
  71. package/src/components/textarea/textarea.css +0 -1
  72. package/src/index.ts +0 -10
  73. package/styles.css +0 -1
  74. package/lib/cjs/components/alert/alert.js +0 -1025
  75. package/lib/cjs/components/alert/alert.js.map +0 -1
  76. package/lib/cjs/components/alert/index.js +0 -20
  77. package/lib/cjs/components/alert/index.js.map +0 -1
  78. package/lib/cjs/components/alert/templates.js +0 -120
  79. package/lib/cjs/components/alert/templates.js.map +0 -1
  80. package/lib/cjs/components/alert/types.js +0 -7
  81. package/lib/cjs/components/alert/types.js.map +0 -1
  82. package/lib/cjs/components/datepicker/config/config.js +0 -42
  83. package/lib/cjs/components/datepicker/config/config.js.map +0 -1
  84. package/lib/cjs/components/datepicker/config/index.js +0 -24
  85. package/lib/cjs/components/datepicker/config/index.js.map +0 -1
  86. package/lib/cjs/components/datepicker/config/interfaces.js +0 -7
  87. package/lib/cjs/components/datepicker/config/interfaces.js.map +0 -1
  88. package/lib/cjs/components/datepicker/config/types.js +0 -7
  89. package/lib/cjs/components/datepicker/config/types.js.map +0 -1
  90. package/lib/cjs/components/datepicker/core/event-manager.js +0 -135
  91. package/lib/cjs/components/datepicker/core/event-manager.js.map +0 -1
  92. package/lib/cjs/components/datepicker/core/focus-manager.js +0 -167
  93. package/lib/cjs/components/datepicker/core/focus-manager.js.map +0 -1
  94. package/lib/cjs/components/datepicker/core/helpers.js +0 -219
  95. package/lib/cjs/components/datepicker/core/helpers.js.map +0 -1
  96. package/lib/cjs/components/datepicker/core/index.js +0 -25
  97. package/lib/cjs/components/datepicker/core/index.js.map +0 -1
  98. package/lib/cjs/components/datepicker/core/unified-state-manager.js +0 -394
  99. package/lib/cjs/components/datepicker/core/unified-state-manager.js.map +0 -1
  100. package/lib/cjs/components/datepicker/datepicker.js +0 -2252
  101. package/lib/cjs/components/datepicker/datepicker.js.map +0 -1
  102. package/lib/cjs/components/datepicker/index.js +0 -24
  103. package/lib/cjs/components/datepicker/index.js.map +0 -1
  104. package/lib/cjs/components/datepicker/ui/index.js +0 -23
  105. package/lib/cjs/components/datepicker/ui/index.js.map +0 -1
  106. package/lib/cjs/components/datepicker/ui/input/dropdown.js +0 -489
  107. package/lib/cjs/components/datepicker/ui/input/dropdown.js.map +0 -1
  108. package/lib/cjs/components/datepicker/ui/input/index.js +0 -23
  109. package/lib/cjs/components/datepicker/ui/input/index.js.map +0 -1
  110. package/lib/cjs/components/datepicker/ui/input/segmented-input.js +0 -640
  111. package/lib/cjs/components/datepicker/ui/input/segmented-input.js.map +0 -1
  112. package/lib/cjs/components/datepicker/ui/renderers/calendar.js +0 -446
  113. package/lib/cjs/components/datepicker/ui/renderers/calendar.js.map +0 -1
  114. package/lib/cjs/components/datepicker/ui/renderers/footer.js +0 -42
  115. package/lib/cjs/components/datepicker/ui/renderers/footer.js.map +0 -1
  116. package/lib/cjs/components/datepicker/ui/renderers/header.js +0 -32
  117. package/lib/cjs/components/datepicker/ui/renderers/header.js.map +0 -1
  118. package/lib/cjs/components/datepicker/ui/renderers/index.js +0 -25
  119. package/lib/cjs/components/datepicker/ui/renderers/index.js.map +0 -1
  120. package/lib/cjs/components/datepicker/ui/renderers/time-picker.js +0 -384
  121. package/lib/cjs/components/datepicker/ui/renderers/time-picker.js.map +0 -1
  122. package/lib/cjs/components/datepicker/ui/templates/index.js +0 -22
  123. package/lib/cjs/components/datepicker/ui/templates/index.js.map +0 -1
  124. package/lib/cjs/components/datepicker/ui/templates/templates.js +0 -253
  125. package/lib/cjs/components/datepicker/ui/templates/templates.js.map +0 -1
  126. package/lib/cjs/components/datepicker/utils/date-formatters.js +0 -88
  127. package/lib/cjs/components/datepicker/utils/date-formatters.js.map +0 -1
  128. package/lib/cjs/components/datepicker/utils/date-utils.js +0 -194
  129. package/lib/cjs/components/datepicker/utils/date-utils.js.map +0 -1
  130. package/lib/cjs/components/datepicker/utils/index.js +0 -24
  131. package/lib/cjs/components/datepicker/utils/index.js.map +0 -1
  132. package/lib/cjs/components/datepicker/utils/time-utils.js +0 -213
  133. package/lib/cjs/components/datepicker/utils/time-utils.js.map +0 -1
  134. package/lib/esm/components/alert/alert.js +0 -1022
  135. package/lib/esm/components/alert/alert.js.map +0 -1
  136. package/lib/esm/components/alert/index.js +0 -4
  137. package/lib/esm/components/alert/index.js.map +0 -1
  138. package/lib/esm/components/alert/templates.js +0 -112
  139. package/lib/esm/components/alert/templates.js.map +0 -1
  140. package/lib/esm/components/alert/types.js +0 -6
  141. package/lib/esm/components/alert/types.js.map +0 -1
  142. package/lib/esm/components/datepicker/config/config.js +0 -39
  143. package/lib/esm/components/datepicker/config/config.js.map +0 -1
  144. package/lib/esm/components/datepicker/config/index.js +0 -8
  145. package/lib/esm/components/datepicker/config/index.js.map +0 -1
  146. package/lib/esm/components/datepicker/config/interfaces.js +0 -6
  147. package/lib/esm/components/datepicker/config/interfaces.js.map +0 -1
  148. package/lib/esm/components/datepicker/config/types.js +0 -6
  149. package/lib/esm/components/datepicker/config/types.js.map +0 -1
  150. package/lib/esm/components/datepicker/core/event-manager.js +0 -133
  151. package/lib/esm/components/datepicker/core/event-manager.js.map +0 -1
  152. package/lib/esm/components/datepicker/core/focus-manager.js +0 -164
  153. package/lib/esm/components/datepicker/core/focus-manager.js.map +0 -1
  154. package/lib/esm/components/datepicker/core/helpers.js +0 -211
  155. package/lib/esm/components/datepicker/core/helpers.js.map +0 -1
  156. package/lib/esm/components/datepicker/core/index.js +0 -9
  157. package/lib/esm/components/datepicker/core/index.js.map +0 -1
  158. package/lib/esm/components/datepicker/core/unified-state-manager.js +0 -391
  159. package/lib/esm/components/datepicker/core/unified-state-manager.js.map +0 -1
  160. package/lib/esm/components/datepicker/datepicker.js +0 -2248
  161. package/lib/esm/components/datepicker/datepicker.js.map +0 -1
  162. package/lib/esm/components/datepicker/index.js +0 -7
  163. package/lib/esm/components/datepicker/index.js.map +0 -1
  164. package/lib/esm/components/datepicker/ui/index.js +0 -7
  165. package/lib/esm/components/datepicker/ui/index.js.map +0 -1
  166. package/lib/esm/components/datepicker/ui/input/dropdown.js +0 -486
  167. package/lib/esm/components/datepicker/ui/input/dropdown.js.map +0 -1
  168. package/lib/esm/components/datepicker/ui/input/index.js +0 -7
  169. package/lib/esm/components/datepicker/ui/input/index.js.map +0 -1
  170. package/lib/esm/components/datepicker/ui/input/segmented-input.js +0 -637
  171. package/lib/esm/components/datepicker/ui/input/segmented-input.js.map +0 -1
  172. package/lib/esm/components/datepicker/ui/renderers/calendar.js +0 -443
  173. package/lib/esm/components/datepicker/ui/renderers/calendar.js.map +0 -1
  174. package/lib/esm/components/datepicker/ui/renderers/footer.js +0 -39
  175. package/lib/esm/components/datepicker/ui/renderers/footer.js.map +0 -1
  176. package/lib/esm/components/datepicker/ui/renderers/header.js +0 -29
  177. package/lib/esm/components/datepicker/ui/renderers/header.js.map +0 -1
  178. package/lib/esm/components/datepicker/ui/renderers/index.js +0 -9
  179. package/lib/esm/components/datepicker/ui/renderers/index.js.map +0 -1
  180. package/lib/esm/components/datepicker/ui/renderers/time-picker.js +0 -381
  181. package/lib/esm/components/datepicker/ui/renderers/time-picker.js.map +0 -1
  182. package/lib/esm/components/datepicker/ui/templates/index.js +0 -6
  183. package/lib/esm/components/datepicker/ui/templates/index.js.map +0 -1
  184. package/lib/esm/components/datepicker/ui/templates/templates.js +0 -242
  185. package/lib/esm/components/datepicker/ui/templates/templates.js.map +0 -1
  186. package/lib/esm/components/datepicker/utils/date-formatters.js +0 -83
  187. package/lib/esm/components/datepicker/utils/date-formatters.js.map +0 -1
  188. package/lib/esm/components/datepicker/utils/date-utils.js +0 -184
  189. package/lib/esm/components/datepicker/utils/date-utils.js.map +0 -1
  190. package/lib/esm/components/datepicker/utils/index.js +0 -8
  191. package/lib/esm/components/datepicker/utils/index.js.map +0 -1
  192. package/lib/esm/components/datepicker/utils/time-utils.js +0 -201
  193. package/lib/esm/components/datepicker/utils/time-utils.js.map +0 -1
  194. package/src/components/alert/alert.ts +0 -990
  195. package/src/components/alert/index.ts +0 -4
  196. package/src/components/alert/templates.ts +0 -110
  197. package/src/components/alert/tests/accessibility/aria-roles.test.ts +0 -19
  198. package/src/components/alert/tests/accessibility/focus-management.test.ts +0 -19
  199. package/src/components/alert/tests/accessibility/keyboard-nav.test.ts +0 -22
  200. package/src/components/alert/tests/actions/confirm-cancel.test.ts +0 -122
  201. package/src/components/alert/tests/actions/input-field.test.ts +0 -180
  202. package/src/components/alert/tests/alert.basic.test.ts +0 -126
  203. package/src/components/alert/tests/alert.config.test.ts +0 -75
  204. package/src/components/alert/tests/alert.templates.test.ts +0 -17
  205. package/src/components/alert/tests/config/attribute-config.test.ts +0 -94
  206. package/src/components/alert/tests/config/json-config.test.ts +0 -119
  207. package/src/components/alert/tests/config/merging.test.ts +0 -89
  208. package/src/components/alert/tests/dismissal/auto-dismiss.test.ts +0 -96
  209. package/src/components/alert/tests/dismissal/escape-key-dismiss.test.ts +0 -105
  210. package/src/components/alert/tests/dismissal/manual-dismiss.test.ts +0 -90
  211. package/src/components/alert/tests/dismissal/outside-click-dismiss.test.ts +0 -91
  212. package/src/components/alert/tests/edge-cases/invalid-config.test.ts +0 -19
  213. package/src/components/alert/tests/edge-cases/multiple-alerts.test.ts +0 -19
  214. package/src/components/alert/tests/rendering/custom-content.test.ts +0 -81
  215. package/src/components/alert/tests/rendering/info-alert.test.ts +0 -84
  216. package/src/components/alert/tests/rendering/success-alert.test.ts +0 -100
  217. package/src/components/alert/tests/templates/default-templates.test.ts +0 -16
  218. package/src/components/alert/tests/templates/user-templates.test.ts +0 -16
  219. package/src/components/alert/types.ts +0 -145
  220. package/src/components/datepicker/__tests__/datepicker-events.test.ts +0 -356
  221. package/src/components/datepicker/__tests__/datepicker-init.test.ts +0 -343
  222. package/src/components/datepicker/__tests__/datepicker-integration.test.ts +0 -435
  223. package/src/components/datepicker/__tests__/datepicker-timezone.test.ts +0 -220
  224. package/src/components/datepicker/__tests__/segmented-input-focus.test.ts +0 -380
  225. package/src/components/datepicker/__tests__/selective-state-updates.test.ts +0 -400
  226. package/src/components/datepicker/__tests__/state-manager.test.ts +0 -421
  227. package/src/components/datepicker/__tests__/time-preservation.test.ts +0 -387
  228. package/src/components/datepicker/config/config.ts +0 -40
  229. package/src/components/datepicker/config/index.ts +0 -8
  230. package/src/components/datepicker/config/interfaces.ts +0 -82
  231. package/src/components/datepicker/config/types.ts +0 -188
  232. package/src/components/datepicker/core/event-manager.ts +0 -159
  233. package/src/components/datepicker/core/focus-manager.ts +0 -201
  234. package/src/components/datepicker/core/helpers.ts +0 -231
  235. package/src/components/datepicker/core/index.ts +0 -9
  236. package/src/components/datepicker/core/unified-state-manager.ts +0 -459
  237. package/src/components/datepicker/datepicker.css +0 -435
  238. package/src/components/datepicker/datepicker.ts +0 -2548
  239. package/src/components/datepicker/index.ts +0 -8
  240. package/src/components/datepicker/ui/index.ts +0 -7
  241. package/src/components/datepicker/ui/input/dropdown.ts +0 -552
  242. package/src/components/datepicker/ui/input/index.ts +0 -7
  243. package/src/components/datepicker/ui/input/segmented-input.ts +0 -638
  244. package/src/components/datepicker/ui/renderers/__tests__/calendar-optimizations.test.ts +0 -611
  245. package/src/components/datepicker/ui/renderers/calendar.ts +0 -530
  246. package/src/components/datepicker/ui/renderers/footer.ts +0 -43
  247. package/src/components/datepicker/ui/renderers/header.ts +0 -33
  248. package/src/components/datepicker/ui/renderers/index.ts +0 -9
  249. package/src/components/datepicker/ui/renderers/time-picker.ts +0 -438
  250. package/src/components/datepicker/ui/templates/index.ts +0 -6
  251. package/src/components/datepicker/ui/templates/templates.ts +0 -306
  252. package/src/components/datepicker/utils/__tests__/date-formatters.test.ts +0 -160
  253. package/src/components/datepicker/utils/__tests__/date-utils-keys.test.ts +0 -86
  254. package/src/components/datepicker/utils/__tests__/date-utils-timezone.test.ts +0 -215
  255. package/src/components/datepicker/utils/date-formatters.ts +0 -85
  256. package/src/components/datepicker/utils/date-utils.ts +0 -172
  257. package/src/components/datepicker/utils/index.ts +0 -8
  258. package/src/components/datepicker/utils/time-utils.ts +0 -221
@@ -1,640 +0,0 @@
1
- "use strict";
2
- /*
3
- * segmented-input.ts - Modular segmented input for KTDatepicker (2025+)
4
- * Each date/time part is rendered as a focusable, editable segment.
5
- *
6
- * Features:
7
- * - Segments: day, month, year, (optionally hour, minute, second, AM/PM)
8
- * - Keyboard navigation: Tab, Shift+Tab, arrow keys, Enter
9
- * - Direct typing/editing of segments with focus preservation
10
- * - ARIA roles and accessibility for all segments
11
- * - Emits change events on value update (debounced)
12
- * - Integrates with KTDatepicker for value sync
13
- *
14
- * Keyboard Navigation:
15
- * - Tab/Shift+Tab: Move between segments
16
- * - Arrow Left/Right: Move between segments
17
- * - Arrow Up/Down: Increment/decrement segment value
18
- * - Enter: Move to next segment (wraps from last to first)
19
- * - Number keys: Direct input with validation (optimized for performance)
20
- *
21
- * Performance Optimizations:
22
- * - No DOM re-rendering during number typing
23
- * - Focus preserved during rapid input
24
- * - Debounced onChange events (150ms delay)
25
- * - Caret position maintained during editing
26
- */
27
- Object.defineProperty(exports, "__esModule", { value: true });
28
- exports.SegmentedInput = SegmentedInput;
29
- var templates_1 = require("../templates/templates");
30
- /**
31
- * SegmentedInput - renders a segmented date/time input.
32
- * @param container - HTMLElement to render into
33
- * @param options - SegmentedInputOptions
34
- * @returns cleanup function
35
- */
36
- function SegmentedInput(container, options) {
37
- // --- Internal state ---
38
- var currentValue = new Date(options.value);
39
- var segments = options.segments || ['month', 'day', 'year'];
40
- var locale = options.locale || 'default';
41
- // Global flag to track arrow navigation across all segmented inputs
42
- if (!window.__ktui_segmented_input_arrow_navigation) {
43
- window.__ktui_segmented_input_arrow_navigation = false;
44
- }
45
- // --- Get templates ---
46
- // Use a minimal config to get templates; in real usage, pass full config if available
47
- var templates = (0, templates_1.getTemplateStrings)({});
48
- var segmentTpl = templates.dateSegment;
49
- var separatorTpl = templates.segmentSeparator;
50
- // --- Utility: get separator between segments ---
51
- function getSeparatorBetweenSegments(segment1, segment2, format) {
52
- // Time segments use ":" as separator
53
- var timeSegments = ['hour', 'minute', 'second'];
54
- if (timeSegments.includes(segment1) && timeSegments.includes(segment2)) {
55
- return ':';
56
- }
57
- // Space between date and time
58
- var dateSegments = ['day', 'month', 'year'];
59
- if (dateSegments.includes(segment1) && timeSegments.includes(segment2)) {
60
- return ' ';
61
- }
62
- // AM/PM has space before it
63
- if (segment2 === 'ampm') {
64
- return ' ';
65
- }
66
- // Second to AM/PM has space
67
- if (segment1 === 'second' && segment2 === 'ampm') {
68
- return ' ';
69
- }
70
- // Date segments use separator from format
71
- if (dateSegments.includes(segment1) && dateSegments.includes(segment2)) {
72
- return getSeparatorFromFormat(format);
73
- }
74
- // Default fallback
75
- return '';
76
- }
77
- // --- Utility: get separator from format ---
78
- function getSeparatorFromFormat(format) {
79
- if (!format)
80
- return '/'; // Default fallback
81
- // Find the first non-date token character to use as separator
82
- var tokenRegex = /(yyyy|yy|MM|M|dd|d)/g;
83
- var lastIndex = 0;
84
- var match;
85
- while ((match = tokenRegex.exec(format)) !== null) {
86
- if (match.index > lastIndex) {
87
- // Found a separator character
88
- var separator = format.slice(lastIndex, match.index);
89
- if (separator && separator.length > 0) {
90
- return separator;
91
- }
92
- }
93
- lastIndex = match.index + match[0].length;
94
- }
95
- // Check for separator after the last token
96
- if (lastIndex < format.length) {
97
- var separator = format.slice(lastIndex);
98
- if (separator && separator.length > 0) {
99
- return separator;
100
- }
101
- }
102
- return '/'; // Default fallback
103
- }
104
- // --- Utility: check if segment should be padded based on format ---
105
- function shouldPadSegment(segment, format) {
106
- if (!format)
107
- return true; // Default to padded for backward compatibility
108
- var tokenRegex = /(yyyy|yy|MM|M|dd|d|HH|H|mm|m|ss|s)/g;
109
- var match;
110
- while ((match = tokenRegex.exec(format)) !== null) {
111
- switch (match[0]) {
112
- case 'dd':
113
- if (segment === 'day')
114
- return true;
115
- break;
116
- case 'd':
117
- if (segment === 'day')
118
- return false;
119
- break;
120
- case 'MM':
121
- if (segment === 'month')
122
- return true;
123
- break;
124
- case 'M':
125
- if (segment === 'month')
126
- return false;
127
- break;
128
- case 'yyyy':
129
- if (segment === 'year')
130
- return true;
131
- break; // 4-digit year
132
- case 'yy':
133
- if (segment === 'year')
134
- return false;
135
- break; // 2-digit year
136
- case 'HH':
137
- case 'H':
138
- if (segment === 'hour')
139
- return match[0] === 'HH';
140
- break;
141
- case 'mm':
142
- case 'm':
143
- if (segment === 'minute')
144
- return match[0] === 'mm';
145
- break;
146
- case 'ss':
147
- case 's':
148
- if (segment === 'second')
149
- return match[0] === 'ss';
150
- break;
151
- }
152
- }
153
- return true; // Default fallback
154
- }
155
- // --- Utility: get segment value as string ---
156
- function getSegmentValue(segment, date) {
157
- var shouldPad = shouldPadSegment(segment, options.format);
158
- switch (segment) {
159
- case 'day':
160
- var day = date.getDate();
161
- return shouldPad ? day.toString().padStart(2, '0') : day.toString();
162
- case 'month':
163
- var month = date.getMonth() + 1;
164
- return shouldPad ? month.toString().padStart(2, '0') : month.toString();
165
- case 'year':
166
- var year = date.getFullYear();
167
- return shouldPad ? year.toString() : year.toString().slice(-2); // yy format shows last 2 digits
168
- case 'hour':
169
- // For 12-hour format, convert to 1-12 range
170
- var hourValue = void 0;
171
- if (options.timeFormat === '12h') {
172
- var hour24 = date.getHours();
173
- hourValue = hour24 === 0 ? 12 : hour24 > 12 ? hour24 - 12 : hour24;
174
- }
175
- else {
176
- hourValue = date.getHours();
177
- }
178
- return shouldPad ? hourValue.toString().padStart(2, '0') : hourValue.toString();
179
- case 'minute':
180
- var minute = date.getMinutes();
181
- return shouldPad ? minute.toString().padStart(2, '0') : minute.toString();
182
- case 'second':
183
- var second = date.getSeconds();
184
- return shouldPad ? second.toString().padStart(2, '0') : second.toString();
185
- case 'ampm': return date.getHours() < 12 ? 'AM' : 'PM';
186
- default: return '';
187
- }
188
- }
189
- // --- Utility: set segment value ---
190
- function setSegmentValue(segment, value, date) {
191
- var d = new Date(date);
192
- switch (segment) {
193
- case 'day':
194
- d.setDate(Number(value));
195
- break;
196
- case 'month':
197
- d.setMonth(Number(value) - 1);
198
- break;
199
- case 'year':
200
- d.setFullYear(Number(value));
201
- break;
202
- case 'hour':
203
- // Handle 12-hour vs 24-hour format
204
- var hourValue = Number(value);
205
- if (options.timeFormat === '12h') {
206
- // In 12-hour mode, convert 12-hour input to 24-hour
207
- var currentHour = d.getHours();
208
- var isPM = currentHour >= 12;
209
- if (hourValue === 12) {
210
- hourValue = isPM ? 12 : 0; // 12 AM = 0, 12 PM = 12
211
- }
212
- else if (isPM) {
213
- hourValue += 12; // PM hours: add 12
214
- }
215
- }
216
- // Preserve existing minutes and seconds when setting hour
217
- var currentMinutes = d.getMinutes();
218
- var currentSecondsForHour = d.getSeconds();
219
- d.setHours(hourValue, currentMinutes, currentSecondsForHour);
220
- break;
221
- case 'minute':
222
- // Preserve existing seconds when setting minute
223
- var currentSecondsForMinute = d.getSeconds();
224
- d.setMinutes(Number(value), currentSecondsForMinute);
225
- break;
226
- case 'second':
227
- d.setSeconds(Number(value));
228
- break;
229
- case 'ampm':
230
- if (value === 'AM' && d.getHours() >= 12) {
231
- d.setHours(d.getHours() - 12);
232
- }
233
- else if (value === 'PM' && d.getHours() < 12) {
234
- d.setHours(d.getHours() + 12);
235
- }
236
- break;
237
- }
238
- return d;
239
- }
240
- // --- Utility: get min/max for a segment ---
241
- function getSegmentMin(segment, date) {
242
- switch (segment) {
243
- case 'day':
244
- // Use actual month/year for max days
245
- return 1;
246
- case 'month':
247
- return 1;
248
- case 'year':
249
- return options.min ? options.min.getFullYear() : undefined;
250
- case 'hour':
251
- return 0;
252
- case 'minute':
253
- case 'second':
254
- return 0;
255
- case 'ampm':
256
- return 0; // 0 = AM, 1 = PM
257
- default:
258
- return undefined;
259
- }
260
- }
261
- function getSegmentMax(segment, date) {
262
- switch (segment) {
263
- case 'day':
264
- // Use actual month/year for max days
265
- return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
266
- case 'month':
267
- return 12;
268
- case 'year':
269
- return options.max ? options.max.getFullYear() : undefined;
270
- case 'hour':
271
- return 23;
272
- case 'minute':
273
- case 'second':
274
- return 59;
275
- case 'ampm':
276
- return 1; // 0 = AM, 1 = PM
277
- default:
278
- return undefined;
279
- }
280
- }
281
- // --- Track focused segment index ---
282
- var focusedIdx = 0;
283
- // --- Track caret position (offset) ---
284
- var caretOffset = null;
285
- // --- Track if this is the first render ---
286
- var isInitialRender = true;
287
- // --- Track if we're in the middle of Arrow Up/Down navigation ---
288
- var isArrowNavigation = false;
289
- // --- Focus a segment by index and restore caret position ---
290
- /**
291
- * Restores focus to the segment at the given index and restores caret position if available.
292
- * @param idx - Index of the segment to focus
293
- * @param caret - Caret offset to restore (null for end)
294
- */
295
- function restoreFocus(idx, caret) {
296
- var _a;
297
- if (caret === void 0) { caret = null; }
298
- try {
299
- var segs = Array.from(container.querySelectorAll('[data-segment]'));
300
- if (segs[idx] && segs[idx].offsetParent !== null) { // Check if element is in DOM
301
- segs.forEach(function (el, i) { return el.setAttribute('tabindex', i === idx ? '0' : '-1'); });
302
- segs[idx].focus();
303
- // Restore caret position (at end if null)
304
- if (segs[idx].isContentEditable) {
305
- var range = document.createRange();
306
- range.selectNodeContents(segs[idx]);
307
- range.collapse(false); // place at end
308
- if (caret !== null && segs[idx].firstChild) {
309
- range.setStart(segs[idx].firstChild, Math.min(caret, ((_a = segs[idx].textContent) === null || _a === void 0 ? void 0 : _a.length) || 0));
310
- range.collapse(true);
311
- }
312
- var sel = window.getSelection();
313
- if (sel) {
314
- sel.removeAllRanges();
315
- sel.addRange(range);
316
- }
317
- }
318
- }
319
- }
320
- catch (error) {
321
- // Fallback: focus first available segment
322
- var segs = Array.from(container.querySelectorAll('[data-segment]'));
323
- if (segs[0])
324
- segs[0].focus();
325
- }
326
- }
327
- // --- Render segments using templates ---
328
- function render() {
329
- // Capture caret position before DOM update
330
- var prevSegs = Array.from(container.querySelectorAll('[data-segment]'));
331
- if (prevSegs[focusedIdx] && document.activeElement === prevSegs[focusedIdx]) {
332
- var sel = window.getSelection();
333
- if (sel && sel.anchorNode === prevSegs[focusedIdx].firstChild) {
334
- caretOffset = sel.anchorOffset;
335
- }
336
- else {
337
- caretOffset = null;
338
- }
339
- }
340
- else {
341
- caretOffset = null;
342
- }
343
- container.innerHTML = '';
344
- container.setAttribute('role', 'group');
345
- container.setAttribute('aria-label', 'Date input');
346
- container.tabIndex = -1;
347
- // Build segments HTML using templates
348
- var segmentsHtml = '';
349
- segments.forEach(function (segment, idx) {
350
- var _a, _b, _c, _d;
351
- var segmentValue = getSegmentValue(segment, currentValue);
352
- var segmentData = {
353
- segmentType: segment,
354
- segmentValue: segmentValue,
355
- ariaLabel: segment.charAt(0).toUpperCase() + segment.slice(1),
356
- ariaValueNow: segmentValue,
357
- ariaValueText: segmentValue,
358
- ariaValueMin: (_b = (_a = getSegmentMin(segment, currentValue)) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : '',
359
- ariaValueMax: (_d = (_c = getSegmentMax(segment, currentValue)) === null || _c === void 0 ? void 0 : _c.toString()) !== null && _d !== void 0 ? _d : '',
360
- tabindex: idx === focusedIdx ? '0' : '-1',
361
- contenteditable: (!options.disabled && !options.readOnly).toString(),
362
- };
363
- var segmentHtml = '';
364
- if (typeof segmentTpl === 'function') {
365
- segmentHtml = segmentTpl(segmentData);
366
- }
367
- else if (typeof segmentTpl === 'string') {
368
- segmentHtml = segmentTpl
369
- .replace(/{{segmentType}}/g, segmentData.segmentType)
370
- .replace(/{{segmentValue}}/g, segmentData.segmentValue)
371
- .replace(/{{ariaLabel}}/g, segmentData.ariaLabel)
372
- .replace(/{{ariaValueNow}}/g, segmentData.ariaValueNow)
373
- .replace(/{{ariaValueText}}/g, segmentData.ariaValueText)
374
- .replace(/{{ariaValueMin}}/g, segmentData.ariaValueMin)
375
- .replace(/{{ariaValueMax}}/g, segmentData.ariaValueMax)
376
- .replace(/{{tabindex}}/g, segmentData.tabindex)
377
- .replace(/{{contenteditable}}/g, segmentData.contenteditable)
378
- .replace(/{{class}}/g, ''); // Replace class placeholder with empty string
379
- }
380
- else {
381
- segmentHtml = '';
382
- }
383
- segmentsHtml += segmentHtml;
384
- if (idx < segments.length - 1) {
385
- // Get appropriate separator between these segments
386
- var nextSegment = segments[idx + 1];
387
- var separator = getSeparatorBetweenSegments(segment, nextSegment, options.format);
388
- var sepHtml = '';
389
- if (typeof separatorTpl === 'function') {
390
- sepHtml = separatorTpl({ separator: separator });
391
- }
392
- else if (typeof separatorTpl === 'string') {
393
- sepHtml = separatorTpl
394
- .replace(/{{separator}}/g, separator)
395
- .replace(/{{class}}/g, ''); // Replace class placeholder with empty string
396
- }
397
- else {
398
- sepHtml = '';
399
- }
400
- segmentsHtml += sepHtml;
401
- }
402
- });
403
- // Render segments directly into container (container already has the correct structure from template)
404
- container.innerHTML = segmentsHtml;
405
- // Verify template rendering was successful
406
- var segs = Array.from(container.querySelectorAll('[data-segment]'));
407
- if (segs.length === 0) {
408
- throw new Error('Segmented input template rendering failed');
409
- }
410
- // Re-bind events to all segments
411
- segs.forEach(function (span, idx) {
412
- span.addEventListener('keydown', function (e) {
413
- var _a, _b, _c, _d;
414
- if (options.disabled || options.readOnly)
415
- return;
416
- // Wrapping navigation
417
- if (e.key === 'ArrowRight' || (e.key === 'Tab' && !e.shiftKey)) {
418
- e.preventDefault();
419
- isArrowNavigation = true; // Set flag to prevent blur onChange
420
- focusedIdx = (idx + 1) % segments.length;
421
- caretOffset = null;
422
- // Update tabindex directly instead of full re-render
423
- var segs_1 = Array.from(container.querySelectorAll('[data-segment]'));
424
- segs_1.forEach(function (el, i) { return el.setAttribute('tabindex', i === focusedIdx ? '0' : '-1'); });
425
- restoreFocus(focusedIdx, caretOffset);
426
- // Reset flag after a short delay to allow focus to be restored
427
- setTimeout(function () {
428
- isArrowNavigation = false;
429
- }, 10);
430
- }
431
- else if (e.key === 'ArrowLeft' || (e.key === 'Tab' && e.shiftKey)) {
432
- e.preventDefault();
433
- isArrowNavigation = true; // Set flag to prevent blur onChange
434
- focusedIdx = (idx - 1 + segments.length) % segments.length;
435
- caretOffset = null;
436
- // Update tabindex directly instead of full re-render
437
- var segs_2 = Array.from(container.querySelectorAll('[data-segment]'));
438
- segs_2.forEach(function (el, i) { return el.setAttribute('tabindex', i === focusedIdx ? '0' : '-1'); });
439
- restoreFocus(focusedIdx, caretOffset);
440
- // Reset flag after a short delay to allow focus to be restored
441
- setTimeout(function () {
442
- isArrowNavigation = false;
443
- }, 10);
444
- }
445
- else if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
446
- // Increment/decrement value
447
- e.preventDefault();
448
- e.stopPropagation(); // Prevent bubbling to main datepicker
449
- isArrowNavigation = true; // Set flag to prevent blur onChange
450
- var newValue = void 0;
451
- if (segments[idx] === 'ampm') {
452
- // Handle AM/PM toggle
453
- var currentAmPm = span.textContent || 'AM';
454
- if (e.key === 'ArrowUp') {
455
- newValue = currentAmPm === 'AM' ? 'PM' : 'AM';
456
- }
457
- else {
458
- newValue = currentAmPm === 'AM' ? 'PM' : 'AM';
459
- }
460
- }
461
- else {
462
- // Handle numeric segments
463
- var min = (_a = getSegmentMin(segments[idx], currentValue)) !== null && _a !== void 0 ? _a : 0;
464
- var max = (_b = getSegmentMax(segments[idx], currentValue)) !== null && _b !== void 0 ? _b : 9999;
465
- var current = Number(getSegmentValue(segments[idx], currentValue)) || min;
466
- if (e.key === 'ArrowUp') {
467
- current = Math.min(max, current + 1);
468
- }
469
- else if (e.key === 'ArrowDown') {
470
- current = Math.max(min, current - 1);
471
- }
472
- newValue = current.toString();
473
- var shouldPad = shouldPadSegment(segments[idx], options.format);
474
- if (segments[idx] === 'year') {
475
- if (shouldPad) {
476
- newValue = newValue.padStart(4, '0');
477
- }
478
- }
479
- else if (shouldPad) {
480
- newValue = newValue.padStart(2, '0');
481
- }
482
- }
483
- span.textContent = newValue;
484
- currentValue = setSegmentValue(segments[idx], newValue, currentValue);
485
- // Set global flag to prevent unified observer from overriding UI
486
- window.__ktui_segmented_input_arrow_navigation = true;
487
- // Call onChange immediately for Arrow Up/Down to update the main datepicker
488
- if (options.onChange) {
489
- options.onChange(currentValue);
490
- }
491
- // Clear flag after onChange callback
492
- setTimeout(function () {
493
- window.__ktui_segmented_input_arrow_navigation = false;
494
- }, 50);
495
- // Preserve caret position at end of content
496
- if (span.isContentEditable) {
497
- var range = document.createRange();
498
- range.selectNodeContents(span);
499
- range.collapse(false); // place at end
500
- var sel = window.getSelection();
501
- if (sel) {
502
- sel.removeAllRanges();
503
- sel.addRange(range);
504
- }
505
- }
506
- // Reset flag after a short delay to allow focus to be restored
507
- setTimeout(function () {
508
- isArrowNavigation = false;
509
- }, 10);
510
- }
511
- else if (e.key === 'Enter') {
512
- // Move to next segment on Enter
513
- e.preventDefault();
514
- e.stopPropagation(); // Prevent bubbling to main datepicker
515
- isArrowNavigation = true; // Set flag to prevent blur onChange
516
- focusedIdx = (idx + 1) % segments.length;
517
- caretOffset = null;
518
- // Update tabindex directly instead of full re-render
519
- var segs_3 = Array.from(container.querySelectorAll('[data-segment]'));
520
- segs_3.forEach(function (el, i) { return el.setAttribute('tabindex', i === focusedIdx ? '0' : '-1'); });
521
- restoreFocus(focusedIdx, caretOffset);
522
- // Reset flag after a short delay to allow focus to be restored
523
- setTimeout(function () {
524
- isArrowNavigation = false;
525
- }, 10);
526
- }
527
- else if (/^[0-9]$/.test(e.key)) {
528
- // Direct typing, enforce min/max - optimized to avoid focus loss
529
- e.preventDefault();
530
- var newValue = void 0;
531
- var currentText = span.textContent || '';
532
- if (segments[idx] === 'year') {
533
- // For year: shift left and append new digit (e.g., "2024" + "6" = "0246", then becomes "2026" after validation)
534
- // If already 4 digits, shift left by removing first digit and appending new one
535
- if (currentText.length === 4) {
536
- newValue = (currentText.slice(1) + e.key);
537
- }
538
- else {
539
- newValue = (currentText + e.key).slice(-4);
540
- }
541
- }
542
- else {
543
- // For day/month: shift left and append new digit (e.g., "12" + "5" = "25")
544
- // If already 2 digits, shift left by removing first digit and appending new one
545
- if (currentText.length === 2) {
546
- newValue = (currentText.slice(1) + e.key);
547
- }
548
- else {
549
- newValue = (currentText + e.key).slice(-2);
550
- }
551
- }
552
- var min = (_c = getSegmentMin(segments[idx], currentValue)) !== null && _c !== void 0 ? _c : 0;
553
- var max = (_d = getSegmentMax(segments[idx], currentValue)) !== null && _d !== void 0 ? _d : (segments[idx] === 'year' ? 9999 : 99);
554
- var num = Math.max(min, Math.min(max, Number(newValue)));
555
- if (isNaN(num))
556
- num = min;
557
- // Update content directly without re-rendering to preserve focus
558
- var shouldPad = shouldPadSegment(segments[idx], options.format);
559
- if (segments[idx] === 'year') {
560
- span.textContent = shouldPad ? num.toString().padStart(4, '0') : num.toString();
561
- }
562
- else {
563
- span.textContent = shouldPad ? num.toString().padStart(2, '0') : num.toString();
564
- }
565
- // Update internal value
566
- currentValue = setSegmentValue(segments[idx], span.textContent || '', currentValue);
567
- // Debounce onChange to avoid excessive updates during rapid typing
568
- if (options.onChange) {
569
- clearTimeout(span._onChangeTimeout);
570
- span._onChangeTimeout = setTimeout(function () {
571
- options.onChange(currentValue);
572
- }, 150); // 150ms debounce
573
- }
574
- // Preserve caret position at end of content
575
- if (span.isContentEditable) {
576
- var range = document.createRange();
577
- range.selectNodeContents(span);
578
- range.collapse(false); // place at end
579
- var sel = window.getSelection();
580
- if (sel) {
581
- sel.removeAllRanges();
582
- sel.addRange(range);
583
- }
584
- }
585
- }
586
- });
587
- // Focus/blur styling (no classes, just ARIA/tabindex)
588
- span.addEventListener('focus', function () {
589
- span.setAttribute('tabindex', '0');
590
- focusedIdx = idx;
591
- });
592
- span.addEventListener('blur', function () {
593
- span.setAttribute('tabindex', '-1');
594
- // Clear any pending debounced onChange calls
595
- if (span._onChangeTimeout) {
596
- clearTimeout(span._onChangeTimeout);
597
- span._onChangeTimeout = null;
598
- }
599
- // Call onChange when user finishes editing to update the main datepicker
600
- // But not during Arrow Up/Down navigation and only if value actually changed
601
- if (options.onChange && !isArrowNavigation) {
602
- var updatedValue = setSegmentValue(segments[idx], span.textContent || '', currentValue);
603
- // Only call onChange if the value has actually changed
604
- if (updatedValue.getTime() !== currentValue.getTime()) {
605
- options.onChange(updatedValue);
606
- }
607
- }
608
- });
609
- // Mouse click focuses segment (optimized to avoid unnecessary re-rendering)
610
- span.addEventListener('mousedown', function (e) {
611
- e.preventDefault();
612
- focusedIdx = idx;
613
- caretOffset = null;
614
- // Only update tabindex and focus, no full re-render
615
- var segs = Array.from(container.querySelectorAll('[data-segment]'));
616
- segs.forEach(function (el, i) { return el.setAttribute('tabindex', i === focusedIdx ? '0' : '-1'); });
617
- restoreFocus(focusedIdx, caretOffset);
618
- });
619
- });
620
- // After rendering, restore focus to the correct segment and caret (skip on initial render)
621
- if (!isInitialRender) {
622
- restoreFocus(focusedIdx, caretOffset);
623
- }
624
- isInitialRender = false;
625
- }
626
- // --- Initial render ---
627
- render();
628
- // --- Cleanup function ---
629
- return function () {
630
- // Clear any pending debounced onChange calls
631
- var segs = Array.from(container.querySelectorAll('[data-segment]'));
632
- segs.forEach(function (span) {
633
- if (span._onChangeTimeout) {
634
- clearTimeout(span._onChangeTimeout);
635
- }
636
- });
637
- container.innerHTML = '';
638
- };
639
- }
640
- //# sourceMappingURL=segmented-input.js.map