@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,4 @@
1
+ // index.ts - Barrel export for KTAlert component and types
2
+
3
+ export * from './alert';
4
+ export * from './types';
@@ -0,0 +1,110 @@
1
+ /*
2
+ * templates.ts - Default templates and merging logic for KTAlert (modular alert/dialog component)
3
+ * Defines all default template strings and provides merged template set.
4
+ *
5
+ * Accessibility: All templates include ARIA roles and attributes for screen reader and keyboard support.
6
+ */
7
+
8
+ import { KTAlertConfig, KTAlertTemplateStrings } from './types';
9
+
10
+ // Core template strings for all UI fragments
11
+ export const coreTemplateStrings: KTAlertTemplateStrings = {
12
+ // Overlay: wraps the modal for modal alerts
13
+ overlay: `<div data-kt-alert-overlay aria-hidden="false" class="kt-alert-overlay {{class}}">{{modal}}</div>`,
14
+ // Modal container: role=alertdialog for modal, role=alert for non-modal
15
+ modal: `<div data-kt-alert data-kt-alert-type="{{type}}" data-kt-alert-variant="{{variant}}" aria-modal="{{ariaModal}}" role="{{role}}" aria-label="Alert Dialog" class="kt-alert-modal {{class}}" data-kt-alert-position="{{position}}">{{content}}</div>`,
16
+ // Fallback container (non-modal, or if no template provided)
17
+ container: `<div class="kt-alert-container {{class}}">{{content}}</div>`,
18
+ icon: `<span data-kt-alert-icon aria-hidden="true" class="kt-alert-icon {{class}}">{{icon}}</span>`,
19
+ title: `<h2 data-kt-alert-title id="kt-alert-title" class="kt-alert-title {{class}}">{{title}}</h2>`,
20
+ message: `<div data-kt-alert-message id="kt-alert-message" class="kt-alert-message {{class}}">{{message}}</div>`,
21
+ actions: `<div data-kt-alert-actions class="kt-alert-actions {{class}}">{{confirmButton}} {{cancelButton}}</div>`,
22
+ // Confirm/cancel buttons (default, can be overridden with custom class)
23
+ confirmButton: `<button type="button" data-kt-alert-confirm aria-label="Confirm" tabindex="0" class="kt-alert-confirm-button {{class}}">{{confirmText}}</button>`,
24
+ cancelButton: `<button type="button" data-kt-alert-cancel aria-label="Cancel" tabindex="0" class="kt-alert-cancel-button {{class}}">{{cancelText}}</button>`,
25
+ // Confirm/cancel buttons with custom class (for per-type theming)
26
+ confirmButtonCustomClass: `<button type="button" data-kt-alert-confirm aria-label="Confirm" tabindex="0" class="{{confirmButtonClass}}">{{confirmText}}</button>`,
27
+ cancelButtonCustomClass: `<button type="button" data-kt-alert-cancel aria-label="Cancel" tabindex="0" class="{{cancelButtonClass}}">{{cancelText}}</button>`,
28
+ // Input templates for each type
29
+ inputText: `<label data-kt-alert-input-label class="kt-alert-input-label {{inputLabelClass}}">{{inputLabel}}<input data-kt-alert-input type="{{inputType}}" placeholder="{{inputPlaceholder}}" value="{{inputValue}}" {{attrs}} aria-label="Prompt input" tabindex="0" class="kt-alert-input {{inputClass}}" /></label>`,
30
+ inputTextarea: `<label data-kt-alert-input-label class="kt-alert-input-label {{inputLabelClass}}">{{inputLabel}}<textarea data-kt-alert-input placeholder="{{inputPlaceholder}}" {{attrs}} aria-label="Prompt input" tabindex="0" class="kt-alert-input {{inputClass}}">{{inputValue}}</textarea></label>`,
31
+ inputSelect: `<label data-kt-alert-input-label class="kt-alert-input-label {{inputLabelClass}}">{{inputLabel}}<select data-kt-alert-input {{attrs}} aria-label="Prompt input" tabindex="0" class="kt-alert-input {{inputClass}}">{{optionsHtml}}</select></label>`,
32
+ inputRadio: `<fieldset data-kt-alert-input-label class="kt-alert-input-label {{inputLabelClass}}"><legend>{{inputLabel}}</legend>{{optionsHtml}}</fieldset>`,
33
+ inputCheckbox: `<fieldset data-kt-alert-input-label class="kt-alert-input-label {{inputLabelClass}}"><legend>{{inputLabel}}</legend>{{optionsHtml}}</fieldset>`,
34
+ inputError: `<div data-kt-alert-input-error class="kt-alert-input-error {{class}}" role="alert" aria-live="polite">{{errorMessage}}</div>`,
35
+ closeButton: `<button type="button" data-kt-alert-close aria-label="Close alert" tabindex="0" class="kt-alert-close-button {{class}}">&times;</button>`,
36
+ customContent: `<div data-kt-alert-custom-content class="kt-alert-custom-content {{class}}">{{customContent}}</div>`,
37
+ loaderHtml: `<span data-kt-alert-loader class="kt-alert-loader {{class}}">{{loaderHtml}}</span>`,
38
+ // Input option templates
39
+ option: `<option value="{{value}}"{{selected}} {{disabled}}>{{label}}</option>`,
40
+ radioOption: `<label><input type="radio" name="kt-alert-radio" data-kt-alert-input value="{{value}}"{{checked}} {{disabled}} {{attrs}} aria-label="{{label}}" tabindex="0" />{{label}}</label>`,
41
+ checkboxOption: `<label><input type="checkbox" name="kt-alert-checkbox" data-kt-alert-input value="{{value}}"{{checked}} {{disabled}} {{attrs}} aria-label="{{label}}" tabindex="0" />{{label}}</label>`,
42
+ };
43
+
44
+ /**
45
+ * Get the complete template set, merging defaults, user overrides, and config templates.
46
+ * @param config Optional config object with a "templates" property.
47
+ */
48
+ export function getTemplateStrings(config?: KTAlertConfig): KTAlertTemplateStrings {
49
+ const templates = config?.templates;
50
+ if (templates) {
51
+ return { ...coreTemplateStrings, ...userTemplateStrings, ...templates };
52
+ }
53
+ return { ...coreTemplateStrings, ...userTemplateStrings };
54
+ }
55
+
56
+ /**
57
+ * Renders a template string with data using {{key}} placeholders.
58
+ */
59
+ export function renderTemplateString(template: string, data: Record<string, any>): string {
60
+ return template.replace(/{{(\w+)}}/g, (_, key) =>
61
+ data[key] !== undefined ? String(data[key]) : ''
62
+ );
63
+ }
64
+
65
+ /**
66
+ * Checks if a template is a function.
67
+ */
68
+ export function isTemplateFunction(tpl: unknown): tpl is (data: any) => string {
69
+ return typeof tpl === 'function';
70
+ }
71
+
72
+ /**
73
+ * User-supplied template overrides. Use setTemplateStrings() to add or update.
74
+ */
75
+ let userTemplateStrings: Partial<typeof coreTemplateStrings> = {};
76
+
77
+ /**
78
+ * Register or update user template overrides.
79
+ * @param templates Partial template object to merge with defaults.
80
+ */
81
+ export function setTemplateStrings(templates: Partial<typeof coreTemplateStrings>): void {
82
+ userTemplateStrings = { ...userTemplateStrings, ...templates };
83
+ }
84
+
85
+ /**
86
+ * Renders an array of options using a template.
87
+ */
88
+ export function renderOptions(options: Array<any>, templateKey: string, templateSet: KTAlertTemplateStrings): string {
89
+ const template = templateSet[templateKey as keyof KTAlertTemplateStrings];
90
+ if (!template) return '';
91
+
92
+ return options.map(option => {
93
+ const data = {
94
+ value: option.value,
95
+ label: option.label,
96
+ selected: option.value === option.inputValue ? ' selected' : '',
97
+ checked: option.checked || false ? ' checked' : '',
98
+ disabled: option.disabled || false ? ' disabled' : '',
99
+ attrs: option.attrs || ''
100
+ };
101
+
102
+ if (isTemplateFunction(template)) {
103
+ return template(data);
104
+ } else if (typeof template === 'string') {
105
+ return renderTemplateString(template, data);
106
+ }
107
+ return '';
108
+ }).join('');
109
+ }
110
+
@@ -0,0 +1,19 @@
1
+ /**
2
+ * TEST SUITE: ARIA Roles & Attributes
3
+ * PURPOSE: Test ARIA roles/attributes for modal and non-modal alerts
4
+ * SCOPE: KTAlert ARIA roles and attributes
5
+ * DEPENDENCIES: vitest, jsdom
6
+ * LAST UPDATED: 2024-06-08
7
+ */
8
+
9
+ import { describe, it, expect } from 'vitest';
10
+ import { KTAlert } from '../../alert';
11
+
12
+ describe('KTAlert ARIA roles and attributes', () => {
13
+ it('should set correct ARIA roles and attributes for modal alert', () => {
14
+ // TODO: Implement test
15
+ });
16
+ it('should set correct ARIA roles and attributes for non-modal alert', () => {
17
+ // TODO: Implement test
18
+ });
19
+ });
@@ -0,0 +1,19 @@
1
+ /**
2
+ * TEST SUITE: Focus Management
3
+ * PURPOSE: Test initial focus and focus trap in modal alerts
4
+ * SCOPE: KTAlert focus management
5
+ * DEPENDENCIES: vitest, jsdom
6
+ * LAST UPDATED: 2024-06-08
7
+ */
8
+
9
+ import { describe, it, expect } from 'vitest';
10
+ import { KTAlert } from '../../alert';
11
+
12
+ describe('KTAlert focus management', () => {
13
+ it('should focus first interactive element on open', () => {
14
+ // TODO: Implement test
15
+ });
16
+ it('should trap focus within modal when open', () => {
17
+ // TODO: Implement test
18
+ });
19
+ });
@@ -0,0 +1,22 @@
1
+ /**
2
+ * TEST SUITE: Keyboard Navigation
3
+ * PURPOSE: Test Tab/Shift+Tab navigation, Enter/Space activation, Escape to close
4
+ * SCOPE: KTAlert keyboard navigation
5
+ * DEPENDENCIES: vitest, jsdom
6
+ * LAST UPDATED: 2024-06-08
7
+ */
8
+
9
+ import { describe, it, expect } from 'vitest';
10
+ import { KTAlert } from '../../alert';
11
+
12
+ describe('KTAlert keyboard navigation', () => {
13
+ it('should allow Tab and Shift+Tab navigation between interactive elements', () => {
14
+ // TODO: Implement test
15
+ });
16
+ it('should activate confirm on Enter/Space', () => {
17
+ // TODO: Implement test
18
+ });
19
+ it('should close alert on Escape if allowed', () => {
20
+ // TODO: Implement test
21
+ });
22
+ });
@@ -0,0 +1,122 @@
1
+ /**
2
+ * TEST SUITE: Confirm/Cancel Actions
3
+ * PURPOSE: Test confirm and cancel button flows, event firing, and result values
4
+ * SCOPE: KTAlert confirm/cancel actions
5
+ * DEPENDENCIES: vitest, jsdom
6
+ * LAST UPDATED: 2024-06-08
7
+ */
8
+
9
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
10
+ import { KTAlert } from '../../alert';
11
+
12
+ describe('KTAlert confirm/cancel actions', () => {
13
+ beforeEach(() => {
14
+ document.body.innerHTML = '';
15
+ });
16
+ afterEach(() => {
17
+ document.body.innerHTML = '';
18
+ });
19
+
20
+ it('should fire confirm event and resolve with correct value', () => {
21
+ // ARRANGE
22
+ const element = document.createElement('div');
23
+ document.body.appendChild(element);
24
+ const alert = new KTAlert(element, { showConfirmButton: true });
25
+ const fireEventSpy = vi.spyOn(alert as any, '_fireEvent');
26
+ // ACT
27
+ const confirmButton = element.querySelector('[data-kt-alert-confirm]') as HTMLElement;
28
+ confirmButton?.click();
29
+ // ASSERT
30
+ expect(fireEventSpy).toHaveBeenCalledWith('confirm', { inputValue: undefined });
31
+ expect((alert as any)._state.isDismissed).toBe(true);
32
+ expect(element.innerHTML).toBe('');
33
+ });
34
+
35
+ it('should fire cancel event and resolve with correct value', () => {
36
+ // ARRANGE
37
+ const element = document.createElement('div');
38
+ document.body.appendChild(element);
39
+ const alert = new KTAlert(element, { showCancelButton: true });
40
+ const fireEventSpy = vi.spyOn(alert as any, '_fireEvent');
41
+ // ACT
42
+ const cancelButton = element.querySelector('[data-kt-alert-cancel]') as HTMLElement;
43
+ cancelButton?.click();
44
+ // ASSERT
45
+ expect(fireEventSpy).toHaveBeenCalledWith('cancel', {});
46
+ expect((alert as any)._state.isDismissed).toBe(true);
47
+ expect(element.innerHTML).toBe('');
48
+ });
49
+
50
+ it('should use custom button text if provided', () => {
51
+ // ARRANGE
52
+ const element = document.createElement('div');
53
+ document.body.appendChild(element);
54
+ const alert = new KTAlert(element, {
55
+ showConfirmButton: true,
56
+ showCancelButton: true,
57
+ confirmText: 'Yes, do it!',
58
+ cancelText: 'No, cancel'
59
+ });
60
+ // ACT
61
+ const confirmButton = element.querySelector('[data-kt-alert-confirm]') as HTMLElement;
62
+ const cancelButton = element.querySelector('[data-kt-alert-cancel]') as HTMLElement;
63
+ // ASSERT
64
+ expect(confirmButton?.textContent).toBe('Yes, do it!');
65
+ expect(cancelButton?.textContent).toBe('No, cancel');
66
+ });
67
+
68
+ it('should not render buttons if showConfirmButton and showCancelButton are false', () => {
69
+ // ARRANGE
70
+ const element = document.createElement('div');
71
+ document.body.appendChild(element);
72
+ const alert = new KTAlert(element, {
73
+ showConfirmButton: false,
74
+ showCancelButton: false
75
+ });
76
+ // ACT
77
+ const confirmButton = element.querySelector('[data-kt-alert-confirm]');
78
+ const cancelButton = element.querySelector('[data-kt-alert-cancel]');
79
+ // ASSERT
80
+ expect(confirmButton).toBeNull();
81
+ expect(cancelButton).toBeNull();
82
+ });
83
+
84
+ it('should clear timer when confirm button is clicked', () => {
85
+ // ARRANGE
86
+ const element = document.createElement('div');
87
+ document.body.appendChild(element);
88
+ const alert = new KTAlert(element, { showConfirmButton: true, timer: 5000 });
89
+ const clearTimerSpy = vi.spyOn(alert as any, '_clearTimer');
90
+ // ACT
91
+ const confirmButton = element.querySelector('[data-kt-alert-confirm]') as HTMLElement;
92
+ confirmButton?.click();
93
+ // ASSERT
94
+ expect(clearTimerSpy).toHaveBeenCalled();
95
+ });
96
+
97
+ it('should clear timer when cancel button is clicked', () => {
98
+ // ARRANGE
99
+ const element = document.createElement('div');
100
+ document.body.appendChild(element);
101
+ const alert = new KTAlert(element, { showCancelButton: true, timer: 5000 });
102
+ const clearTimerSpy = vi.spyOn(alert as any, '_clearTimer');
103
+ // ACT
104
+ const cancelButton = element.querySelector('[data-kt-alert-cancel]') as HTMLElement;
105
+ cancelButton?.click();
106
+ // ASSERT
107
+ expect(clearTimerSpy).toHaveBeenCalled();
108
+ });
109
+
110
+ it('should handle Enter key to trigger confirm button', () => {
111
+ // ARRANGE
112
+ const config = { showConfirmButton: true, title: 'Test' };
113
+ // ACT
114
+ KTAlert.fire(config);
115
+ const alert = document.querySelector('[data-kt-alert]');
116
+ const enterEvent = new KeyboardEvent('keydown', { key: 'Enter', bubbles: true });
117
+ alert?.dispatchEvent(enterEvent);
118
+ // ASSERT
119
+ // The alert should be dismissed (confirm button clicked)
120
+ expect(document.querySelector('[data-kt-alert-overlay]')).toBeNull();
121
+ });
122
+ });
@@ -0,0 +1,180 @@
1
+ /**
2
+ * TEST SUITE: Input Field Actions
3
+ * PURPOSE: Test alerts with input fields (text, textarea, select, radio, checkbox), value propagation
4
+ * SCOPE: KTAlert input field handling
5
+ * DEPENDENCIES: vitest, jsdom
6
+ * LAST UPDATED: 2024-06-08
7
+ */
8
+
9
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
10
+ import { KTAlert } from '../../alert';
11
+
12
+ describe('KTAlert input field actions', () => {
13
+ beforeEach(() => {
14
+ document.body.innerHTML = '';
15
+ });
16
+ afterEach(() => {
17
+ document.body.innerHTML = '';
18
+ });
19
+
20
+ it('should propagate value from text input', () => {
21
+ // ARRANGE
22
+ const config = {
23
+ input: true,
24
+ inputType: 'text',
25
+ inputPlaceholder: 'Enter text',
26
+ showConfirmButton: true,
27
+ title: 'Test'
28
+ };
29
+ // ACT
30
+ KTAlert.fire(config);
31
+ const input = document.querySelector('input[type="text"]') as HTMLInputElement;
32
+ input.value = 'test value';
33
+ const confirmButton = document.querySelector('[data-kt-alert-confirm]') as HTMLElement;
34
+ confirmButton?.click();
35
+ // ASSERT
36
+ // The alert should be dismissed with the input value
37
+ expect(document.querySelector('[data-kt-alert-overlay]')).toBeNull();
38
+ });
39
+
40
+ it('should propagate value from textarea input', () => {
41
+ // ARRANGE
42
+ const config = {
43
+ input: true,
44
+ inputType: 'textarea',
45
+ inputPlaceholder: 'Enter text',
46
+ showConfirmButton: true,
47
+ title: 'Test'
48
+ };
49
+ // ACT
50
+ KTAlert.fire(config);
51
+ const textarea = document.querySelector('textarea') as HTMLTextAreaElement;
52
+ textarea.value = 'multiline\ntext';
53
+ const confirmButton = document.querySelector('[data-kt-alert-confirm]') as HTMLElement;
54
+ confirmButton?.click();
55
+ // ASSERT
56
+ // The alert should be dismissed with the input value
57
+ expect(document.querySelector('[data-kt-alert-overlay]')).toBeNull();
58
+ });
59
+
60
+ it('should propagate value from select input', () => {
61
+ // ARRANGE
62
+ const config = {
63
+ input: true,
64
+ inputType: 'select',
65
+ inputOptions: [
66
+ { value: 'option1', label: 'Option 1' },
67
+ { value: 'option2', label: 'Option 2' }
68
+ ],
69
+ showConfirmButton: true,
70
+ title: 'Test'
71
+ };
72
+ // ACT
73
+ KTAlert.fire(config);
74
+ const select = document.querySelector('select') as HTMLSelectElement;
75
+ select.value = 'option2';
76
+ const confirmButton = document.querySelector('[data-kt-alert-confirm]') as HTMLElement;
77
+ confirmButton?.click();
78
+ // ASSERT
79
+ // The alert should be dismissed with the input value
80
+ expect(document.querySelector('[data-kt-alert-overlay]')).toBeNull();
81
+ });
82
+
83
+ it('should propagate value from radio input', () => {
84
+ // ARRANGE
85
+ const config = {
86
+ input: true,
87
+ inputType: 'radio',
88
+ inputOptions: [
89
+ { value: 'radio1', label: 'Radio 1' },
90
+ { value: 'radio2', label: 'Radio 2', checked: true }
91
+ ],
92
+ showConfirmButton: true,
93
+ title: 'Test'
94
+ };
95
+ // ACT
96
+ KTAlert.fire(config);
97
+ const confirmButton = document.querySelector('[data-kt-alert-confirm]') as HTMLElement;
98
+ confirmButton?.click();
99
+ // ASSERT
100
+ // The alert should be dismissed with the input value
101
+ expect(document.querySelector('[data-kt-alert-overlay]')).toBeNull();
102
+ });
103
+
104
+ it('should propagate value from checkbox input', () => {
105
+ // ARRANGE
106
+ const config = {
107
+ input: true,
108
+ inputType: 'checkbox',
109
+ inputOptions: [
110
+ { value: 'check1', label: 'Check 1' },
111
+ { value: 'check2', label: 'Check 2' }
112
+ ],
113
+ showConfirmButton: true,
114
+ title: 'Test'
115
+ };
116
+ // ACT
117
+ KTAlert.fire(config);
118
+ const checkboxes = document.querySelectorAll('input[type="checkbox"]') as NodeListOf<HTMLInputElement>;
119
+ checkboxes[0].checked = true;
120
+ checkboxes[1].checked = true;
121
+ const confirmButton = document.querySelector('[data-kt-alert-confirm]') as HTMLElement;
122
+ confirmButton?.click();
123
+ // ASSERT
124
+ // The alert should be dismissed with the input value
125
+ expect(document.querySelector('[data-kt-alert-overlay]')).toBeNull();
126
+ });
127
+
128
+ it('should handle input change events', () => {
129
+ // ARRANGE
130
+ const config = {
131
+ input: true,
132
+ inputType: 'text',
133
+ showConfirmButton: true,
134
+ title: 'Test'
135
+ };
136
+ // ACT
137
+ KTAlert.fire(config);
138
+ const input = document.querySelector('input[type="text"]') as HTMLInputElement;
139
+ input.value = 'new value';
140
+ input.dispatchEvent(new Event('input', { bubbles: true }));
141
+ // ASSERT
142
+ // The input value should be updated
143
+ expect(input.value).toBe('new value');
144
+ });
145
+
146
+ it('should not render input if input is false', () => {
147
+ // ARRANGE
148
+ const config = {
149
+ input: false,
150
+ showConfirmButton: true,
151
+ title: 'Test'
152
+ };
153
+ // ACT
154
+ KTAlert.fire(config);
155
+ const input = document.querySelector('input, textarea, select');
156
+ // ASSERT
157
+ expect(input).toBeNull();
158
+ });
159
+
160
+ it('should apply input attributes correctly', () => {
161
+ // ARRANGE
162
+ const config = {
163
+ input: true,
164
+ inputType: 'text',
165
+ inputAttributes: {
166
+ maxlength: '10',
167
+ required: 'true',
168
+ pattern: '[A-Za-z]+'
169
+ },
170
+ title: 'Test'
171
+ };
172
+ // ACT
173
+ KTAlert.fire(config);
174
+ const input = document.querySelector('input[type="text"]') as HTMLInputElement;
175
+ // ASSERT
176
+ expect(input?.getAttribute('maxlength')).toBe('10');
177
+ expect(input?.getAttribute('required')).toBe('true');
178
+ expect(input?.getAttribute('pattern')).toBe('[A-Za-z]+');
179
+ });
180
+ });
@@ -0,0 +1,126 @@
1
+ // alert.basic.test.ts - Basic instantiation and type safety tests for KTAlert
2
+ import { describe, it, expect } from 'vitest';
3
+ import { KTAlert } from '../alert';
4
+ import { vi } from 'vitest';
5
+
6
+ describe('KTAlert', () => {
7
+ it('should instantiate without errors', () => {
8
+ // Create a dummy element
9
+ const el = document.createElement('div');
10
+ // Instantiate KTAlert
11
+ const alert = new KTAlert(document.createElement("div"));
12
+ // Should be defined
13
+ expect(alert).toBeDefined();
14
+ // Should have correct name
15
+ expect((alert as any)._name).toBe('alert');
16
+ });
17
+
18
+ it('should auto-dismiss after timer expires', async () => {
19
+ vi.useFakeTimers();
20
+ const el = document.createElement('div');
21
+ document.body.appendChild(el);
22
+ const alert = new KTAlert(el, { timer: 1000, dismissible: true });
23
+ // Spy on _fireEvent
24
+ const fireEventSpy = vi.spyOn(alert as any, '_fireEvent');
25
+ // Fast-forward time
26
+ vi.advanceTimersByTime(1000);
27
+ // Wait for microtasks
28
+ await vi.runAllTicks();
29
+ expect(fireEventSpy).toHaveBeenCalledWith('dismiss', { reason: 'timer' });
30
+ expect(el.innerHTML).toBe('');
31
+ vi.useRealTimers();
32
+ });
33
+
34
+ it('should not auto-dismiss if manually dismissed first', async () => {
35
+ vi.useFakeTimers();
36
+ const el = document.createElement('div');
37
+ document.body.appendChild(el);
38
+ const alert = new KTAlert(el, { timer: 1000, dismissible: true });
39
+ // Spy on _fireEvent
40
+ const fireEventSpy = vi.spyOn(alert as any, '_fireEvent');
41
+ // Simulate manual dismiss
42
+ (alert as any)._clearTimer();
43
+ (alert as any)._state.isDismissed = true;
44
+ (alert as any)._element.innerHTML = '';
45
+ // Fast-forward time
46
+ vi.advanceTimersByTime(1000);
47
+ // Wait for microtasks
48
+ await vi.runAllTicks();
49
+ // Should not call _fireEvent again for timer
50
+ expect(fireEventSpy).not.toHaveBeenCalledWith('dismiss', { reason: 'timer' });
51
+ vi.useRealTimers();
52
+ });
53
+ });
54
+
55
+ describe('KTAlert input types', () => {
56
+ it('should render and capture text input', () => {
57
+ const el = document.createElement('div');
58
+ document.body.appendChild(el);
59
+ const alert = new KTAlert(el, { input: true, inputType: 'text', inputValue: 'foo' });
60
+ const input = el.querySelector('input[data-kt-alert-input]') as HTMLInputElement;
61
+ expect(input).toBeDefined();
62
+ expect(input.value).toBe('foo');
63
+ input.value = 'bar';
64
+ input.dispatchEvent(new Event('input'));
65
+ expect((alert as any)._state.inputValue).toBe('bar');
66
+ });
67
+
68
+ it('should render and capture textarea input', () => {
69
+ const el = document.createElement('div');
70
+ document.body.appendChild(el);
71
+ const alert = new KTAlert(el, { input: true, inputType: 'textarea', inputValue: 'foo' });
72
+ const textarea = el.querySelector('textarea[data-kt-alert-input]') as HTMLTextAreaElement;
73
+ expect(textarea).toBeDefined();
74
+ expect(textarea.value).toBe('foo');
75
+ textarea.value = 'bar';
76
+ textarea.dispatchEvent(new Event('input'));
77
+ expect((alert as any)._state.inputValue).toBe('bar');
78
+ });
79
+
80
+ it('should render and capture select input', () => {
81
+ const el = document.createElement('div');
82
+ document.body.appendChild(el);
83
+ const alert = new KTAlert(el, { input: true, inputType: 'select', inputValue: 'b', inputOptions: [
84
+ { value: 'a', label: 'A' },
85
+ { value: 'b', label: 'B' },
86
+ { value: 'c', label: 'C' },
87
+ ] });
88
+ const select = el.querySelector('select[data-kt-alert-input]') as HTMLSelectElement;
89
+ expect(select).toBeDefined();
90
+ expect(select.value).toBe('b');
91
+ select.value = 'c';
92
+ select.dispatchEvent(new Event('change'));
93
+ expect((alert as any)._state.inputValue).toBe('c');
94
+ });
95
+
96
+ it('should render and capture radio input', () => {
97
+ const el = document.createElement('div');
98
+ document.body.appendChild(el);
99
+ const alert = new KTAlert(el, { input: true, inputType: 'radio', inputValue: 'b', inputOptions: [
100
+ { value: 'a', label: 'A' },
101
+ { value: 'b', label: 'B' },
102
+ { value: 'c', label: 'C' },
103
+ ] });
104
+ const radios = el.querySelectorAll('input[type="radio"][data-kt-alert-input]') as NodeListOf<HTMLInputElement>;
105
+ expect(radios.length).toBe(3);
106
+ radios[2].checked = true;
107
+ radios[2].dispatchEvent(new Event('change'));
108
+ expect((alert as any)._state.inputValue).toBe('c');
109
+ });
110
+
111
+ it('should render and capture checkbox input', () => {
112
+ const el = document.createElement('div');
113
+ document.body.appendChild(el);
114
+ const alert = new KTAlert(el, { input: true, inputType: 'checkbox', inputOptions: [
115
+ { value: 'a', label: 'A', checked: true },
116
+ { value: 'b', label: 'B' },
117
+ { value: 'c', label: 'C', checked: true },
118
+ ] });
119
+ const checkboxes = el.querySelectorAll('input[type="checkbox"][data-kt-alert-input]') as NodeListOf<HTMLInputElement>;
120
+ expect(checkboxes.length).toBe(3);
121
+ checkboxes[1].checked = true;
122
+ checkboxes[1].dispatchEvent(new Event('change'));
123
+ // Should be comma-separated string of checked values
124
+ expect((alert as any)._state.inputValue.split(',').sort()).toEqual(['a','b','c'].sort());
125
+ });
126
+ });