@keenthemes/ktui 1.1.0 → 1.1.1

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 (222) hide show
  1. package/README.md +0 -27
  2. package/dist/ktui.js +6790 -14063
  3. package/dist/ktui.min.js +1 -1
  4. package/dist/ktui.min.js.map +1 -1
  5. package/dist/styles.css +1132 -2705
  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/index.js +1 -10
  15. package/lib/cjs/index.js.map +1 -1
  16. package/lib/esm/components/datatable/__tests__/pagination-reset.test.js +594 -0
  17. package/lib/esm/components/datatable/__tests__/pagination-reset.test.js.map +1 -0
  18. package/lib/esm/components/datatable/__tests__/race-conditions.test.js +546 -0
  19. package/lib/esm/components/datatable/__tests__/race-conditions.test.js.map +1 -0
  20. package/lib/esm/components/datatable/__tests__/setup.js +58 -0
  21. package/lib/esm/components/datatable/__tests__/setup.js.map +1 -0
  22. package/lib/esm/components/datatable/datatable.js +92 -30
  23. package/lib/esm/components/datatable/datatable.js.map +1 -1
  24. package/lib/esm/index.js +0 -7
  25. package/lib/esm/index.js.map +1 -1
  26. package/package.json +7 -9
  27. package/src/components/alert/alert.css +188 -429
  28. package/src/components/datatable/__tests__/pagination-reset.test.ts +657 -0
  29. package/src/components/datatable/__tests__/race-conditions.test.ts +455 -0
  30. package/src/components/datatable/__tests__/setup.ts +67 -0
  31. package/src/components/datatable/datatable.ts +66 -11
  32. package/src/components/input/input.css +0 -1
  33. package/src/components/select/select.css +0 -1
  34. package/src/components/select/variants.css +4 -0
  35. package/src/components/textarea/textarea.css +0 -1
  36. package/src/index.ts +0 -10
  37. package/styles.css +0 -1
  38. package/lib/cjs/components/alert/alert.js +0 -1025
  39. package/lib/cjs/components/alert/alert.js.map +0 -1
  40. package/lib/cjs/components/alert/index.js +0 -20
  41. package/lib/cjs/components/alert/index.js.map +0 -1
  42. package/lib/cjs/components/alert/templates.js +0 -120
  43. package/lib/cjs/components/alert/templates.js.map +0 -1
  44. package/lib/cjs/components/alert/types.js +0 -7
  45. package/lib/cjs/components/alert/types.js.map +0 -1
  46. package/lib/cjs/components/datepicker/config/config.js +0 -42
  47. package/lib/cjs/components/datepicker/config/config.js.map +0 -1
  48. package/lib/cjs/components/datepicker/config/index.js +0 -24
  49. package/lib/cjs/components/datepicker/config/index.js.map +0 -1
  50. package/lib/cjs/components/datepicker/config/interfaces.js +0 -7
  51. package/lib/cjs/components/datepicker/config/interfaces.js.map +0 -1
  52. package/lib/cjs/components/datepicker/config/types.js +0 -7
  53. package/lib/cjs/components/datepicker/config/types.js.map +0 -1
  54. package/lib/cjs/components/datepicker/core/event-manager.js +0 -135
  55. package/lib/cjs/components/datepicker/core/event-manager.js.map +0 -1
  56. package/lib/cjs/components/datepicker/core/focus-manager.js +0 -167
  57. package/lib/cjs/components/datepicker/core/focus-manager.js.map +0 -1
  58. package/lib/cjs/components/datepicker/core/helpers.js +0 -219
  59. package/lib/cjs/components/datepicker/core/helpers.js.map +0 -1
  60. package/lib/cjs/components/datepicker/core/index.js +0 -25
  61. package/lib/cjs/components/datepicker/core/index.js.map +0 -1
  62. package/lib/cjs/components/datepicker/core/unified-state-manager.js +0 -394
  63. package/lib/cjs/components/datepicker/core/unified-state-manager.js.map +0 -1
  64. package/lib/cjs/components/datepicker/datepicker.js +0 -2252
  65. package/lib/cjs/components/datepicker/datepicker.js.map +0 -1
  66. package/lib/cjs/components/datepicker/index.js +0 -24
  67. package/lib/cjs/components/datepicker/index.js.map +0 -1
  68. package/lib/cjs/components/datepicker/ui/index.js +0 -23
  69. package/lib/cjs/components/datepicker/ui/index.js.map +0 -1
  70. package/lib/cjs/components/datepicker/ui/input/dropdown.js +0 -489
  71. package/lib/cjs/components/datepicker/ui/input/dropdown.js.map +0 -1
  72. package/lib/cjs/components/datepicker/ui/input/index.js +0 -23
  73. package/lib/cjs/components/datepicker/ui/input/index.js.map +0 -1
  74. package/lib/cjs/components/datepicker/ui/input/segmented-input.js +0 -640
  75. package/lib/cjs/components/datepicker/ui/input/segmented-input.js.map +0 -1
  76. package/lib/cjs/components/datepicker/ui/renderers/calendar.js +0 -446
  77. package/lib/cjs/components/datepicker/ui/renderers/calendar.js.map +0 -1
  78. package/lib/cjs/components/datepicker/ui/renderers/footer.js +0 -42
  79. package/lib/cjs/components/datepicker/ui/renderers/footer.js.map +0 -1
  80. package/lib/cjs/components/datepicker/ui/renderers/header.js +0 -32
  81. package/lib/cjs/components/datepicker/ui/renderers/header.js.map +0 -1
  82. package/lib/cjs/components/datepicker/ui/renderers/index.js +0 -25
  83. package/lib/cjs/components/datepicker/ui/renderers/index.js.map +0 -1
  84. package/lib/cjs/components/datepicker/ui/renderers/time-picker.js +0 -384
  85. package/lib/cjs/components/datepicker/ui/renderers/time-picker.js.map +0 -1
  86. package/lib/cjs/components/datepicker/ui/templates/index.js +0 -22
  87. package/lib/cjs/components/datepicker/ui/templates/index.js.map +0 -1
  88. package/lib/cjs/components/datepicker/ui/templates/templates.js +0 -253
  89. package/lib/cjs/components/datepicker/ui/templates/templates.js.map +0 -1
  90. package/lib/cjs/components/datepicker/utils/date-formatters.js +0 -88
  91. package/lib/cjs/components/datepicker/utils/date-formatters.js.map +0 -1
  92. package/lib/cjs/components/datepicker/utils/date-utils.js +0 -194
  93. package/lib/cjs/components/datepicker/utils/date-utils.js.map +0 -1
  94. package/lib/cjs/components/datepicker/utils/index.js +0 -24
  95. package/lib/cjs/components/datepicker/utils/index.js.map +0 -1
  96. package/lib/cjs/components/datepicker/utils/time-utils.js +0 -213
  97. package/lib/cjs/components/datepicker/utils/time-utils.js.map +0 -1
  98. package/lib/esm/components/alert/alert.js +0 -1022
  99. package/lib/esm/components/alert/alert.js.map +0 -1
  100. package/lib/esm/components/alert/index.js +0 -4
  101. package/lib/esm/components/alert/index.js.map +0 -1
  102. package/lib/esm/components/alert/templates.js +0 -112
  103. package/lib/esm/components/alert/templates.js.map +0 -1
  104. package/lib/esm/components/alert/types.js +0 -6
  105. package/lib/esm/components/alert/types.js.map +0 -1
  106. package/lib/esm/components/datepicker/config/config.js +0 -39
  107. package/lib/esm/components/datepicker/config/config.js.map +0 -1
  108. package/lib/esm/components/datepicker/config/index.js +0 -8
  109. package/lib/esm/components/datepicker/config/index.js.map +0 -1
  110. package/lib/esm/components/datepicker/config/interfaces.js +0 -6
  111. package/lib/esm/components/datepicker/config/interfaces.js.map +0 -1
  112. package/lib/esm/components/datepicker/config/types.js +0 -6
  113. package/lib/esm/components/datepicker/config/types.js.map +0 -1
  114. package/lib/esm/components/datepicker/core/event-manager.js +0 -133
  115. package/lib/esm/components/datepicker/core/event-manager.js.map +0 -1
  116. package/lib/esm/components/datepicker/core/focus-manager.js +0 -164
  117. package/lib/esm/components/datepicker/core/focus-manager.js.map +0 -1
  118. package/lib/esm/components/datepicker/core/helpers.js +0 -211
  119. package/lib/esm/components/datepicker/core/helpers.js.map +0 -1
  120. package/lib/esm/components/datepicker/core/index.js +0 -9
  121. package/lib/esm/components/datepicker/core/index.js.map +0 -1
  122. package/lib/esm/components/datepicker/core/unified-state-manager.js +0 -391
  123. package/lib/esm/components/datepicker/core/unified-state-manager.js.map +0 -1
  124. package/lib/esm/components/datepicker/datepicker.js +0 -2248
  125. package/lib/esm/components/datepicker/datepicker.js.map +0 -1
  126. package/lib/esm/components/datepicker/index.js +0 -7
  127. package/lib/esm/components/datepicker/index.js.map +0 -1
  128. package/lib/esm/components/datepicker/ui/index.js +0 -7
  129. package/lib/esm/components/datepicker/ui/index.js.map +0 -1
  130. package/lib/esm/components/datepicker/ui/input/dropdown.js +0 -486
  131. package/lib/esm/components/datepicker/ui/input/dropdown.js.map +0 -1
  132. package/lib/esm/components/datepicker/ui/input/index.js +0 -7
  133. package/lib/esm/components/datepicker/ui/input/index.js.map +0 -1
  134. package/lib/esm/components/datepicker/ui/input/segmented-input.js +0 -637
  135. package/lib/esm/components/datepicker/ui/input/segmented-input.js.map +0 -1
  136. package/lib/esm/components/datepicker/ui/renderers/calendar.js +0 -443
  137. package/lib/esm/components/datepicker/ui/renderers/calendar.js.map +0 -1
  138. package/lib/esm/components/datepicker/ui/renderers/footer.js +0 -39
  139. package/lib/esm/components/datepicker/ui/renderers/footer.js.map +0 -1
  140. package/lib/esm/components/datepicker/ui/renderers/header.js +0 -29
  141. package/lib/esm/components/datepicker/ui/renderers/header.js.map +0 -1
  142. package/lib/esm/components/datepicker/ui/renderers/index.js +0 -9
  143. package/lib/esm/components/datepicker/ui/renderers/index.js.map +0 -1
  144. package/lib/esm/components/datepicker/ui/renderers/time-picker.js +0 -381
  145. package/lib/esm/components/datepicker/ui/renderers/time-picker.js.map +0 -1
  146. package/lib/esm/components/datepicker/ui/templates/index.js +0 -6
  147. package/lib/esm/components/datepicker/ui/templates/index.js.map +0 -1
  148. package/lib/esm/components/datepicker/ui/templates/templates.js +0 -242
  149. package/lib/esm/components/datepicker/ui/templates/templates.js.map +0 -1
  150. package/lib/esm/components/datepicker/utils/date-formatters.js +0 -83
  151. package/lib/esm/components/datepicker/utils/date-formatters.js.map +0 -1
  152. package/lib/esm/components/datepicker/utils/date-utils.js +0 -184
  153. package/lib/esm/components/datepicker/utils/date-utils.js.map +0 -1
  154. package/lib/esm/components/datepicker/utils/index.js +0 -8
  155. package/lib/esm/components/datepicker/utils/index.js.map +0 -1
  156. package/lib/esm/components/datepicker/utils/time-utils.js +0 -201
  157. package/lib/esm/components/datepicker/utils/time-utils.js.map +0 -1
  158. package/src/components/alert/alert.ts +0 -990
  159. package/src/components/alert/index.ts +0 -4
  160. package/src/components/alert/templates.ts +0 -110
  161. package/src/components/alert/tests/accessibility/aria-roles.test.ts +0 -19
  162. package/src/components/alert/tests/accessibility/focus-management.test.ts +0 -19
  163. package/src/components/alert/tests/accessibility/keyboard-nav.test.ts +0 -22
  164. package/src/components/alert/tests/actions/confirm-cancel.test.ts +0 -122
  165. package/src/components/alert/tests/actions/input-field.test.ts +0 -180
  166. package/src/components/alert/tests/alert.basic.test.ts +0 -126
  167. package/src/components/alert/tests/alert.config.test.ts +0 -75
  168. package/src/components/alert/tests/alert.templates.test.ts +0 -17
  169. package/src/components/alert/tests/config/attribute-config.test.ts +0 -94
  170. package/src/components/alert/tests/config/json-config.test.ts +0 -119
  171. package/src/components/alert/tests/config/merging.test.ts +0 -89
  172. package/src/components/alert/tests/dismissal/auto-dismiss.test.ts +0 -96
  173. package/src/components/alert/tests/dismissal/escape-key-dismiss.test.ts +0 -105
  174. package/src/components/alert/tests/dismissal/manual-dismiss.test.ts +0 -90
  175. package/src/components/alert/tests/dismissal/outside-click-dismiss.test.ts +0 -91
  176. package/src/components/alert/tests/edge-cases/invalid-config.test.ts +0 -19
  177. package/src/components/alert/tests/edge-cases/multiple-alerts.test.ts +0 -19
  178. package/src/components/alert/tests/rendering/custom-content.test.ts +0 -81
  179. package/src/components/alert/tests/rendering/info-alert.test.ts +0 -84
  180. package/src/components/alert/tests/rendering/success-alert.test.ts +0 -100
  181. package/src/components/alert/tests/templates/default-templates.test.ts +0 -16
  182. package/src/components/alert/tests/templates/user-templates.test.ts +0 -16
  183. package/src/components/alert/types.ts +0 -145
  184. package/src/components/datepicker/__tests__/datepicker-events.test.ts +0 -356
  185. package/src/components/datepicker/__tests__/datepicker-init.test.ts +0 -343
  186. package/src/components/datepicker/__tests__/datepicker-integration.test.ts +0 -435
  187. package/src/components/datepicker/__tests__/datepicker-timezone.test.ts +0 -220
  188. package/src/components/datepicker/__tests__/segmented-input-focus.test.ts +0 -380
  189. package/src/components/datepicker/__tests__/selective-state-updates.test.ts +0 -400
  190. package/src/components/datepicker/__tests__/state-manager.test.ts +0 -421
  191. package/src/components/datepicker/__tests__/time-preservation.test.ts +0 -387
  192. package/src/components/datepicker/config/config.ts +0 -40
  193. package/src/components/datepicker/config/index.ts +0 -8
  194. package/src/components/datepicker/config/interfaces.ts +0 -82
  195. package/src/components/datepicker/config/types.ts +0 -188
  196. package/src/components/datepicker/core/event-manager.ts +0 -159
  197. package/src/components/datepicker/core/focus-manager.ts +0 -201
  198. package/src/components/datepicker/core/helpers.ts +0 -231
  199. package/src/components/datepicker/core/index.ts +0 -9
  200. package/src/components/datepicker/core/unified-state-manager.ts +0 -459
  201. package/src/components/datepicker/datepicker.css +0 -435
  202. package/src/components/datepicker/datepicker.ts +0 -2548
  203. package/src/components/datepicker/index.ts +0 -8
  204. package/src/components/datepicker/ui/index.ts +0 -7
  205. package/src/components/datepicker/ui/input/dropdown.ts +0 -552
  206. package/src/components/datepicker/ui/input/index.ts +0 -7
  207. package/src/components/datepicker/ui/input/segmented-input.ts +0 -638
  208. package/src/components/datepicker/ui/renderers/__tests__/calendar-optimizations.test.ts +0 -611
  209. package/src/components/datepicker/ui/renderers/calendar.ts +0 -530
  210. package/src/components/datepicker/ui/renderers/footer.ts +0 -43
  211. package/src/components/datepicker/ui/renderers/header.ts +0 -33
  212. package/src/components/datepicker/ui/renderers/index.ts +0 -9
  213. package/src/components/datepicker/ui/renderers/time-picker.ts +0 -438
  214. package/src/components/datepicker/ui/templates/index.ts +0 -6
  215. package/src/components/datepicker/ui/templates/templates.ts +0 -306
  216. package/src/components/datepicker/utils/__tests__/date-formatters.test.ts +0 -160
  217. package/src/components/datepicker/utils/__tests__/date-utils-keys.test.ts +0 -86
  218. package/src/components/datepicker/utils/__tests__/date-utils-timezone.test.ts +0 -215
  219. package/src/components/datepicker/utils/date-formatters.ts +0 -85
  220. package/src/components/datepicker/utils/date-utils.ts +0 -172
  221. package/src/components/datepicker/utils/index.ts +0 -8
  222. 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