@keenthemes/ktui 1.0.29 → 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 (243) 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 +12 -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/lib/cjs/components/datepicker/calendar.js +0 -1061
  199. package/lib/cjs/components/datepicker/calendar.js.map +0 -1
  200. package/lib/cjs/components/datepicker/config.js +0 -332
  201. package/lib/cjs/components/datepicker/config.js.map +0 -1
  202. package/lib/cjs/components/datepicker/dropdown.js +0 -635
  203. package/lib/cjs/components/datepicker/dropdown.js.map +0 -1
  204. package/lib/cjs/components/datepicker/events.js +0 -129
  205. package/lib/cjs/components/datepicker/events.js.map +0 -1
  206. package/lib/cjs/components/datepicker/keyboard.js +0 -536
  207. package/lib/cjs/components/datepicker/keyboard.js.map +0 -1
  208. package/lib/cjs/components/datepicker/locales.js +0 -78
  209. package/lib/cjs/components/datepicker/locales.js.map +0 -1
  210. package/lib/cjs/components/datepicker/templates.js +0 -403
  211. package/lib/cjs/components/datepicker/templates.js.map +0 -1
  212. package/lib/cjs/components/datepicker/types.js +0 -23
  213. package/lib/cjs/components/datepicker/types.js.map +0 -1
  214. package/lib/cjs/components/datepicker/utils.js +0 -524
  215. package/lib/cjs/components/datepicker/utils.js.map +0 -1
  216. package/lib/esm/components/datepicker/calendar.js +0 -1058
  217. package/lib/esm/components/datepicker/calendar.js.map +0 -1
  218. package/lib/esm/components/datepicker/config.js +0 -329
  219. package/lib/esm/components/datepicker/config.js.map +0 -1
  220. package/lib/esm/components/datepicker/dropdown.js +0 -632
  221. package/lib/esm/components/datepicker/dropdown.js.map +0 -1
  222. package/lib/esm/components/datepicker/events.js +0 -126
  223. package/lib/esm/components/datepicker/events.js.map +0 -1
  224. package/lib/esm/components/datepicker/keyboard.js +0 -533
  225. package/lib/esm/components/datepicker/keyboard.js.map +0 -1
  226. package/lib/esm/components/datepicker/locales.js +0 -74
  227. package/lib/esm/components/datepicker/locales.js.map +0 -1
  228. package/lib/esm/components/datepicker/templates.js +0 -390
  229. package/lib/esm/components/datepicker/templates.js.map +0 -1
  230. package/lib/esm/components/datepicker/types.js +0 -20
  231. package/lib/esm/components/datepicker/types.js.map +0 -1
  232. package/lib/esm/components/datepicker/utils.js +0 -508
  233. package/lib/esm/components/datepicker/utils.js.map +0 -1
  234. package/src/components/datepicker/calendar.ts +0 -1397
  235. package/src/components/datepicker/config.ts +0 -368
  236. package/src/components/datepicker/dropdown.ts +0 -757
  237. package/src/components/datepicker/events.ts +0 -149
  238. package/src/components/datepicker/keyboard.ts +0 -646
  239. package/src/components/datepicker/locales.ts +0 -80
  240. package/src/components/datepicker/templates.ts +0 -792
  241. package/src/components/datepicker/types.ts +0 -154
  242. package/src/components/datepicker/utils.ts +0 -631
  243. package/src/components/select/variants.css +0 -4
@@ -0,0 +1,75 @@
1
+ // @vitest-environment jsdom
2
+ // alert.config.test.ts - Config merging logic tests for KTAlert
3
+ import { describe, it, expect } from 'vitest';
4
+ import { KTAlertConfig } from '../types';
5
+ import { KTAlert } from '../alert';
6
+
7
+ // Placeholder test for config merging (to be implemented)
8
+ describe('KTAlert config merging', () => {
9
+ it('should merge default, global, data attributes, JSON config, and user config in correct order', () => {
10
+ // Mock element with data attributes and JSON config
11
+ const el = document.createElement('div');
12
+ el.setAttribute('data-kt-alert-type', 'warning');
13
+ el.setAttribute('data-kt-alert-title', 'From Data Attr');
14
+ el.setAttribute('data-kt-alert-config', JSON.stringify({ title: 'From JSON', dismissible: true }));
15
+ // User config
16
+ const userConfig = { title: 'From User', customContent: 'User Content' };
17
+ // Instantiate KTAlert and build config
18
+ const alert = new KTAlert(document.createElement("div"));
19
+ (alert as any)._element = el;
20
+ (alert as any)._getGlobalConfig = () => ({ type: 'error', message: 'From Global' });
21
+ (alert as any)._buildConfig(userConfig);
22
+ const config = (alert as any)._config;
23
+ // Check precedence
24
+ expect(config.type).toBe('warning'); // data attribute overrides global
25
+ expect(config.title).toBe('From User'); // user config overrides JSON/data/global/default
26
+ expect(config.message).toBe('From Global'); // global overrides default
27
+ expect(config.dismissible).toBe(true); // JSON config overrides data/global/default
28
+ expect(config.customContent).toBe('User Content'); // user config
29
+ });
30
+
31
+ it('should support all new config options and merge them correctly', () => {
32
+ const el = document.createElement('div');
33
+ el.setAttribute('data-kt-alert-icon', 'info');
34
+ el.setAttribute('data-kt-alert-position', 'top');
35
+ el.setAttribute('data-kt-alert-show-confirm-button', 'false');
36
+ el.setAttribute('data-kt-alert-show-cancel-button', 'true');
37
+ el.setAttribute('data-kt-alert-show-close-button', 'false');
38
+ el.setAttribute('data-kt-alert-input-placeholder', 'Enter value');
39
+ el.setAttribute('data-kt-alert-input-type', 'email');
40
+ el.setAttribute('data-kt-alert-input-label', 'Email');
41
+ el.setAttribute('data-kt-alert-input-attributes', JSON.stringify({ maxlength: '10', required: 'true' }));
42
+ el.setAttribute('data-kt-alert-custom-class', 'my-alert');
43
+ el.setAttribute('data-kt-alert-loader-html', '<span>Loading...</span>');
44
+ el.setAttribute('data-kt-alert-allow-outside-click', 'false');
45
+ el.setAttribute('data-kt-alert-allow-escape-key', 'false');
46
+ el.setAttribute('data-kt-alert-focus-confirm', 'false');
47
+ el.setAttribute('data-kt-alert-show-loader-on-confirm', 'true');
48
+ el.setAttribute('data-kt-alert-timer', '5000');
49
+ // User config
50
+ const userConfig = { icon: 'error', position: 'bottom', showConfirmButton: true, showCancelButton: false, showCloseButton: true, inputPlaceholder: 'Override', inputType: 'text', inputLabel: 'Override', inputAttributes: { maxlength: '5' }, customClass: 'user-alert', loaderHtml: '<span>User Loading</span>', allowOutsideClick: true, allowEscapeKey: true, focusConfirm: true, showLoaderOnConfirm: false, timer: 10000 };
51
+ // Instantiate KTAlert and build config
52
+ const alert = new KTAlert(document.createElement('div'));
53
+ (alert as any)._element = el;
54
+ (alert as any)._getGlobalConfig = () => ({ icon: 'question', position: 'center' });
55
+ (alert as any)._buildConfig(userConfig);
56
+ const config = (alert as any)._config;
57
+ // Data attributes should override global, user config should override all
58
+ expect(config.icon).toBe('error'); // user config
59
+ expect(config.position).toBe('bottom'); // user config
60
+ expect(config.showConfirmButton).toBe(true); // user config
61
+ expect(config.showCancelButton).toBe(false); // user config
62
+ expect(config.showCloseButton).toBe(true); // user config
63
+ expect(config.inputPlaceholder).toBe('Override'); // user config
64
+ expect(config.inputType).toBe('text'); // user config
65
+ expect(config.inputLabel).toBe('Override'); // user config
66
+ expect(config.inputAttributes).toEqual({ maxlength: '5' }); // user config
67
+ expect(config.customClass).toBe('user-alert'); // user config
68
+ expect(config.loaderHtml).toBe('<span>User Loading</span>'); // user config
69
+ expect(config.allowOutsideClick).toBe(true); // user config
70
+ expect(config.allowEscapeKey).toBe(true); // user config
71
+ expect(config.focusConfirm).toBe(true); // user config
72
+ expect(config.showLoaderOnConfirm).toBe(false); // user config
73
+ expect(config.timer).toBe(10000); // user config
74
+ });
75
+ });
@@ -0,0 +1,17 @@
1
+ // alert.templates.test.ts - Template merging logic tests for KTAlert
2
+ import { describe, it, expect } from 'vitest';
3
+ import { getTemplateStrings, coreTemplateStrings } from '../templates';
4
+
5
+ describe('KTAlert template merging', () => {
6
+ it('should use default templates if no user templates provided', () => {
7
+ const templates = getTemplateStrings();
8
+ expect(templates).toMatchObject(coreTemplateStrings);
9
+ });
10
+
11
+ it('should override default templates with user templates', () => {
12
+ const userTemplates = { title: '<h1>Custom Title</h1>' };
13
+ const templates = getTemplateStrings({ templates: userTemplates });
14
+ expect(templates.title).toBe('<h1>Custom Title</h1>');
15
+ expect(templates.icon).toBe(coreTemplateStrings.icon);
16
+ });
17
+ });
@@ -0,0 +1,94 @@
1
+ /**
2
+ * TEST SUITE: Attribute Config
3
+ * PURPOSE: Test config via data attributes only
4
+ * SCOPE: KTAlert config from data attributes
5
+ * DEPENDENCIES: vitest, jsdom
6
+ * LAST UPDATED: 2024-06-08
7
+ */
8
+
9
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
10
+ import { KTAlert } from '../../alert';
11
+
12
+ describe('KTAlert attribute config', () => {
13
+ beforeEach(() => {
14
+ document.body.innerHTML = '';
15
+ });
16
+ afterEach(() => {
17
+ document.body.innerHTML = '';
18
+ });
19
+
20
+ it('should read config from data attributes', () => {
21
+ // ARRANGE
22
+ const element = document.createElement('div');
23
+ element.setAttribute('data-kt-alert-type', 'error');
24
+ element.setAttribute('data-kt-alert-title', 'Error Title');
25
+ element.setAttribute('data-kt-alert-message', 'Error Message');
26
+ element.setAttribute('data-kt-alert-icon', 'error');
27
+ document.body.appendChild(element);
28
+ // ACT
29
+ const alert = new KTAlert(element);
30
+ // ASSERT
31
+ expect((alert as any)._config.type).toBe('error');
32
+ expect((alert as any)._config.title).toBe('Error Title');
33
+ expect((alert as any)._config.message).toBe('Error Message');
34
+ expect((alert as any)._config.icon).toBe('error');
35
+ });
36
+
37
+ it('should convert kebab-case attributes to camelCase', () => {
38
+ // ARRANGE
39
+ const element = document.createElement('div');
40
+ element.setAttribute('data-kt-alert-show-confirm-button', 'true');
41
+ element.setAttribute('data-kt-alert-show-cancel-button', 'false');
42
+ element.setAttribute('data-kt-alert-allow-outside-click', 'true');
43
+ document.body.appendChild(element);
44
+ // ACT
45
+ const alert = new KTAlert(element);
46
+ // ASSERT
47
+ expect((alert as any)._config.showConfirmButton).toBe(true);
48
+ expect((alert as any)._config.showCancelButton).toBe(false);
49
+ expect((alert as any)._config.allowOutsideClick).toBe(true);
50
+ });
51
+
52
+ it('should handle string values for non-boolean/non-numeric attributes', () => {
53
+ // ARRANGE
54
+ const element = document.createElement('div');
55
+ element.setAttribute('data-kt-alert-confirm-text', 'Yes, do it!');
56
+ element.setAttribute('data-kt-alert-cancel-text', 'No, cancel');
57
+ element.setAttribute('data-kt-alert-position', 'top');
58
+ document.body.appendChild(element);
59
+ // ACT
60
+ const alert = new KTAlert(element);
61
+ // ASSERT
62
+ expect((alert as any)._config.confirmText).toBe('Yes, do it!');
63
+ expect((alert as any)._config.cancelText).toBe('No, cancel');
64
+ expect((alert as any)._config.position).toBe('top');
65
+ });
66
+
67
+ it('should ignore non-data-kt-alert attributes', () => {
68
+ // ARRANGE
69
+ const element = document.createElement('div');
70
+ element.setAttribute('data-kt-alert-type', 'info');
71
+ element.setAttribute('data-other-attr', 'should-be-ignored');
72
+ element.setAttribute('class', 'some-class');
73
+ document.body.appendChild(element);
74
+ // ACT
75
+ const alert = new KTAlert(element);
76
+ // ASSERT
77
+ expect((alert as any)._config.type).toBe('info');
78
+ expect((alert as any)._config).not.toHaveProperty('data-other-attr');
79
+ expect((alert as any)._config).not.toHaveProperty('class');
80
+ });
81
+
82
+ it('should handle empty attribute values', () => {
83
+ // ARRANGE
84
+ const element = document.createElement('div');
85
+ element.setAttribute('data-kt-alert-title', '');
86
+ element.setAttribute('data-kt-alert-message', '');
87
+ document.body.appendChild(element);
88
+ // ACT
89
+ const alert = new KTAlert(element);
90
+ // ASSERT
91
+ expect((alert as any)._config.title).toBe('');
92
+ expect((alert as any)._config.message).toBe('');
93
+ });
94
+ });
@@ -0,0 +1,119 @@
1
+ /**
2
+ * TEST SUITE: JSON Config
3
+ * PURPOSE: Test config via JSON in data attribute
4
+ * SCOPE: KTAlert config from data-kt-alert-config JSON
5
+ * DEPENDENCIES: vitest, jsdom
6
+ * LAST UPDATED: 2024-06-08
7
+ */
8
+
9
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
10
+ import { KTAlert } from '../../alert';
11
+
12
+ describe('KTAlert JSON config', () => {
13
+ beforeEach(() => {
14
+ document.body.innerHTML = '';
15
+ });
16
+ afterEach(() => {
17
+ document.body.innerHTML = '';
18
+ });
19
+
20
+ it('should read config from data-kt-alert-config JSON', () => {
21
+ // ARRANGE
22
+ const element = document.createElement('div');
23
+ const jsonConfig = {
24
+ type: 'warning',
25
+ title: 'Warning from JSON',
26
+ message: 'This is a warning',
27
+ dismissible: true,
28
+ timer: 3000
29
+ };
30
+ element.setAttribute('data-kt-alert-config', JSON.stringify(jsonConfig));
31
+ document.body.appendChild(element);
32
+ // ACT
33
+ const alert = new KTAlert(element);
34
+ // ASSERT
35
+ expect((alert as any)._config.type).toBe('warning');
36
+ expect((alert as any)._config.title).toBe('Warning from JSON');
37
+ expect((alert as any)._config.message).toBe('This is a warning');
38
+ expect((alert as any)._config.dismissible).toBe(true);
39
+ expect((alert as any)._config.timer).toBe(3000);
40
+ });
41
+
42
+ it('should handle complex nested objects in JSON config', () => {
43
+ // ARRANGE
44
+ const element = document.createElement('div');
45
+ const jsonConfig = {
46
+ inputAttributes: {
47
+ maxlength: '50',
48
+ required: 'true',
49
+ pattern: '[A-Za-z]+'
50
+ },
51
+ inputOptions: [
52
+ { value: 'option1', label: 'Option 1' },
53
+ { value: 'option2', label: 'Option 2', checked: true }
54
+ ]
55
+ };
56
+ element.setAttribute('data-kt-alert-config', JSON.stringify(jsonConfig));
57
+ document.body.appendChild(element);
58
+ // ACT
59
+ const alert = new KTAlert(element);
60
+ // ASSERT
61
+ expect((alert as any)._config.inputAttributes).toEqual({
62
+ maxlength: '50',
63
+ required: 'true',
64
+ pattern: '[A-Za-z]+'
65
+ });
66
+ expect((alert as any)._config.inputOptions).toEqual([
67
+ { value: 'option1', label: 'Option 1' },
68
+ { value: 'option2', label: 'Option 2', checked: true }
69
+ ]);
70
+ });
71
+
72
+ it('should handle invalid JSON gracefully', () => {
73
+ // ARRANGE
74
+ const element = document.createElement('div');
75
+ element.setAttribute('data-kt-alert-config', '{"invalid": json}');
76
+ document.body.appendChild(element);
77
+ // ACT
78
+ const alert = new KTAlert(element);
79
+ // ASSERT
80
+ // Should not throw error and should use defaults
81
+ expect((alert as any)._config).toBeDefined();
82
+ expect((alert as any)._config.type).toBe('info'); // default
83
+ });
84
+
85
+ it('should handle empty JSON config', () => {
86
+ // ARRANGE
87
+ const element = document.createElement('div');
88
+ element.setAttribute('data-kt-alert-config', '{}');
89
+ document.body.appendChild(element);
90
+ // ACT
91
+ const alert = new KTAlert(element);
92
+ // ASSERT
93
+ expect((alert as any)._config).toBeDefined();
94
+ expect((alert as any)._config.type).toBe('info'); // default
95
+ });
96
+
97
+ it('should merge JSON config with data attributes correctly', () => {
98
+ // ARRANGE
99
+ const element = document.createElement('div');
100
+ element.setAttribute('data-kt-alert-type', 'error');
101
+ element.setAttribute('data-kt-alert-title', 'From Attribute');
102
+ const jsonConfig = {
103
+ title: 'From JSON',
104
+ message: 'JSON message',
105
+ dismissible: true
106
+ };
107
+ element.setAttribute('data-kt-alert-config', JSON.stringify(jsonConfig));
108
+ document.body.appendChild(element);
109
+ // ACT
110
+ const alert = new KTAlert(element);
111
+ // ASSERT
112
+ // JSON should override data attributes
113
+ expect((alert as any)._config.title).toBe('From JSON');
114
+ expect((alert as any)._config.message).toBe('JSON message');
115
+ expect((alert as any)._config.dismissible).toBe(true);
116
+ // Data attribute should still be applied
117
+ expect((alert as any)._config.type).toBe('error');
118
+ });
119
+ });
@@ -0,0 +1,89 @@
1
+ /**
2
+ * TEST SUITE: Config Merging
3
+ * PURPOSE: Test config merging order (default, global, data attributes, JSON, user config)
4
+ * SCOPE: KTAlert config merging logic
5
+ * DEPENDENCIES: vitest, jsdom
6
+ * LAST UPDATED: 2024-06-08
7
+ */
8
+
9
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
10
+ import { KTAlert } from '../../alert';
11
+
12
+ describe('KTAlert config merging', () => {
13
+ beforeEach(() => {
14
+ document.body.innerHTML = '';
15
+ });
16
+ afterEach(() => {
17
+ document.body.innerHTML = '';
18
+ });
19
+
20
+ it('should merge configs in correct order of precedence', () => {
21
+ // ARRANGE
22
+ const element = document.createElement('div');
23
+ element.setAttribute('data-kt-alert-type', 'warning');
24
+ element.setAttribute('data-kt-alert-title', 'From Data Attr');
25
+ element.setAttribute('data-kt-alert-config', JSON.stringify({ title: 'From JSON', dismissible: true }));
26
+ document.body.appendChild(element);
27
+ const userConfig = { title: 'From User', customContent: 'User Content' };
28
+ // ACT
29
+ const alert = new KTAlert(element, userConfig);
30
+ // ASSERT
31
+ // Check that user config overrides all others
32
+ expect((alert as any)._config.title).toBe('From User');
33
+ expect((alert as any)._config.customContent).toBe('User Content');
34
+ // Check that JSON config is applied
35
+ expect((alert as any)._config.dismissible).toBe(true);
36
+ // Check that data attribute is applied
37
+ expect((alert as any)._config.type).toBe('warning');
38
+ });
39
+
40
+ it('should handle boolean values correctly from data attributes', () => {
41
+ // ARRANGE
42
+ const element = document.createElement('div');
43
+ element.setAttribute('data-kt-alert-dismissible', 'true');
44
+ element.setAttribute('data-kt-alert-modal', 'false');
45
+ element.setAttribute('data-kt-alert-show-confirm-button', 'true');
46
+ document.body.appendChild(element);
47
+ // ACT
48
+ const alert = new KTAlert(element);
49
+ // ASSERT
50
+ expect((alert as any)._config.dismissible).toBe(true);
51
+ expect((alert as any)._config.modal).toBe(false);
52
+ expect((alert as any)._config.showConfirmButton).toBe(true);
53
+ });
54
+
55
+ it('should handle numeric values correctly from data attributes', () => {
56
+ // ARRANGE
57
+ const element = document.createElement('div');
58
+ element.setAttribute('data-kt-alert-timer', '5000');
59
+ document.body.appendChild(element);
60
+ // ACT
61
+ const alert = new KTAlert(element);
62
+ // ASSERT
63
+ expect((alert as any)._config.timer).toBe(5000);
64
+ });
65
+
66
+ it('should handle JSON parsing errors gracefully', () => {
67
+ // ARRANGE
68
+ const element = document.createElement('div');
69
+ element.setAttribute('data-kt-alert-config', 'invalid json');
70
+ document.body.appendChild(element);
71
+ // ACT
72
+ const alert = new KTAlert(element);
73
+ // ASSERT
74
+ // Should not throw error and should use defaults
75
+ expect((alert as any)._config).toBeDefined();
76
+ expect((alert as any)._config.type).toBe('info'); // default
77
+ });
78
+
79
+ it('should handle inputAttributes JSON parsing', () => {
80
+ // ARRANGE
81
+ const element = document.createElement('div');
82
+ element.setAttribute('data-kt-alert-input-attributes', JSON.stringify({ maxlength: '10', required: 'true' }));
83
+ document.body.appendChild(element);
84
+ // ACT
85
+ const alert = new KTAlert(element);
86
+ // ASSERT
87
+ expect((alert as any)._config.inputAttributes).toEqual({ maxlength: '10', required: 'true' });
88
+ });
89
+ });
@@ -0,0 +1,96 @@
1
+ /**
2
+ * TEST SUITE: Auto Dismissal
3
+ * PURPOSE: Test timer-based auto-dismissal
4
+ * SCOPE: KTAlert auto-dismissal logic
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 auto dismissal', () => {
13
+ beforeEach(() => {
14
+ document.body.innerHTML = '';
15
+ vi.useFakeTimers();
16
+ });
17
+ afterEach(() => {
18
+ document.body.innerHTML = '';
19
+ vi.useRealTimers();
20
+ });
21
+
22
+ it('should auto-dismiss alert after timer expires', async () => {
23
+ // ARRANGE
24
+ const element = document.createElement('div');
25
+ document.body.appendChild(element);
26
+ const alert = new KTAlert(element, { timer: 1000 });
27
+ const fireEventSpy = vi.spyOn(alert as any, '_fireEvent');
28
+ // ACT
29
+ vi.advanceTimersByTime(1000);
30
+ await vi.runAllTicks();
31
+ // ASSERT
32
+ expect(fireEventSpy).toHaveBeenCalledWith('dismiss', { reason: 'timer' });
33
+ expect((alert as any)._state.isDismissed).toBe(true);
34
+ expect(element.innerHTML).toBe('');
35
+ });
36
+
37
+ it('should not auto-dismiss if timer is not set', async () => {
38
+ // ARRANGE
39
+ const element = document.createElement('div');
40
+ document.body.appendChild(element);
41
+ const alert = new KTAlert(element, { timer: undefined });
42
+ const fireEventSpy = vi.spyOn(alert as any, '_fireEvent');
43
+ // ACT
44
+ vi.advanceTimersByTime(5000);
45
+ await vi.runAllTicks();
46
+ // ASSERT
47
+ expect(fireEventSpy).not.toHaveBeenCalledWith('dismiss', { reason: 'timer' });
48
+ expect((alert as any)._state.isDismissed).toBe(false);
49
+ });
50
+
51
+ it('should not auto-dismiss if timer is 0 or negative', async () => {
52
+ // ARRANGE
53
+ const element = document.createElement('div');
54
+ document.body.appendChild(element);
55
+ const alert = new KTAlert(element, { timer: 0 });
56
+ const fireEventSpy = vi.spyOn(alert as any, '_fireEvent');
57
+ // ACT
58
+ vi.advanceTimersByTime(1000);
59
+ await vi.runAllTicks();
60
+ // ASSERT
61
+ expect(fireEventSpy).not.toHaveBeenCalledWith('dismiss', { reason: 'timer' });
62
+ expect((alert as any)._state.isDismissed).toBe(false);
63
+ });
64
+
65
+ it('should not auto-dismiss if manually dismissed first', async () => {
66
+ // ARRANGE
67
+ const element = document.createElement('div');
68
+ document.body.appendChild(element);
69
+ const alert = new KTAlert(element, { timer: 1000, showCloseButton: true });
70
+ const fireEventSpy = vi.spyOn(alert as any, '_fireEvent');
71
+ // ACT
72
+ // Manually dismiss first
73
+ const closeButton = element.querySelector('[data-kt-alert-close]') as HTMLElement;
74
+ closeButton?.click();
75
+ // Then advance timer
76
+ vi.advanceTimersByTime(1000);
77
+ await vi.runAllTicks();
78
+ // ASSERT
79
+ // Should only have manual dismiss, not timer dismiss
80
+ expect(fireEventSpy).toHaveBeenCalledWith('dismiss', {});
81
+ expect(fireEventSpy).not.toHaveBeenCalledWith('dismiss', { reason: 'timer' });
82
+ });
83
+
84
+ it('should clear timer when manually dismissed', async () => {
85
+ // ARRANGE
86
+ const element = document.createElement('div');
87
+ document.body.appendChild(element);
88
+ const alert = new KTAlert(element, { timer: 1000, showCloseButton: true });
89
+ const clearTimerSpy = vi.spyOn(alert as any, '_clearTimer');
90
+ // ACT
91
+ const closeButton = element.querySelector('[data-kt-alert-close]') as HTMLElement;
92
+ closeButton?.click();
93
+ // ASSERT
94
+ expect(clearTimerSpy).toHaveBeenCalled();
95
+ });
96
+ });
@@ -0,0 +1,105 @@
1
+ /**
2
+ * TEST SUITE: Escape Key Dismissal
3
+ * PURPOSE: Test dismissal by pressing Escape key
4
+ * SCOPE: KTAlert Escape key dismissal logic
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 Escape key dismissal', () => {
13
+ beforeEach(() => {
14
+ document.body.innerHTML = '';
15
+ });
16
+ afterEach(() => {
17
+ document.body.innerHTML = '';
18
+ });
19
+
20
+ it('should dismiss alert by pressing Escape key if allowed', () => {
21
+ // ARRANGE
22
+ const config = { allowEscapeKey: true, title: 'Test' };
23
+ // ACT
24
+ KTAlert.fire(config);
25
+ const alert = document.querySelector('[data-kt-alert]');
26
+ // Simulate Escape key press
27
+ const escapeEvent = new KeyboardEvent('keydown', { key: 'Escape', bubbles: true });
28
+ alert?.dispatchEvent(escapeEvent);
29
+ // ASSERT
30
+ // The alert should be dismissed
31
+ expect(document.querySelector('[data-kt-alert-overlay]')).toBeNull();
32
+ });
33
+
34
+ it('should not dismiss if allowEscapeKey is false', () => {
35
+ // ARRANGE
36
+ const config = { allowEscapeKey: false, title: 'Test' };
37
+ // ACT
38
+ KTAlert.fire(config);
39
+ const alert = document.querySelector('[data-kt-alert]');
40
+ // Simulate Escape key press
41
+ const escapeEvent = new KeyboardEvent('keydown', { key: 'Escape', bubbles: true });
42
+ alert?.dispatchEvent(escapeEvent);
43
+ // ASSERT
44
+ // Alert should still be present
45
+ expect(alert).toBeTruthy();
46
+ });
47
+
48
+ it('should dismiss if dismissible is true even when allowEscapeKey is false', () => {
49
+ // ARRANGE
50
+ const config = { dismissible: true, allowEscapeKey: false, title: 'Test' };
51
+ // ACT
52
+ KTAlert.fire(config);
53
+ const alert = document.querySelector('[data-kt-alert]');
54
+ // Simulate Escape key press
55
+ const escapeEvent = new KeyboardEvent('keydown', { key: 'Escape', bubbles: true });
56
+ alert?.dispatchEvent(escapeEvent);
57
+ // ASSERT
58
+ // The alert should be dismissed
59
+ expect(document.querySelector('[data-kt-alert-overlay]')).toBeNull();
60
+ });
61
+
62
+ it('should dismiss if modal is true even when allowEscapeKey is false', () => {
63
+ // ARRANGE
64
+ const config = { modal: true, allowEscapeKey: false, title: 'Test' };
65
+ // ACT
66
+ KTAlert.fire(config);
67
+ const alert = document.querySelector('[data-kt-alert]');
68
+ // Simulate Escape key press
69
+ const escapeEvent = new KeyboardEvent('keydown', { key: 'Escape', bubbles: true });
70
+ alert?.dispatchEvent(escapeEvent);
71
+ // ASSERT
72
+ // The alert should be dismissed
73
+ expect(document.querySelector('[data-kt-alert-overlay]')).toBeNull();
74
+ });
75
+
76
+ it('should not dismiss for other key presses', () => {
77
+ // ARRANGE
78
+ const config = { allowEscapeKey: true, title: 'Test' };
79
+ // ACT
80
+ KTAlert.fire(config);
81
+ const alert = document.querySelector('[data-kt-alert]');
82
+ // Simulate other key presses
83
+ const enterEvent = new KeyboardEvent('keydown', { key: 'Enter', bubbles: true });
84
+ const spaceEvent = new KeyboardEvent('keydown', { key: ' ', bubbles: true });
85
+ alert?.dispatchEvent(enterEvent);
86
+ alert?.dispatchEvent(spaceEvent);
87
+ // ASSERT
88
+ // Alert should still be present
89
+ expect(alert).toBeTruthy();
90
+ });
91
+
92
+ it('should clear timer when dismissed by Escape key', () => {
93
+ // ARRANGE
94
+ const config = { allowEscapeKey: true, timer: 5000, title: 'Test' };
95
+ // ACT
96
+ KTAlert.fire(config);
97
+ const alert = document.querySelector('[data-kt-alert]');
98
+ // Simulate Escape key press
99
+ const escapeEvent = new KeyboardEvent('keydown', { key: 'Escape', bubbles: true });
100
+ alert?.dispatchEvent(escapeEvent);
101
+ // ASSERT
102
+ // The overlay should be removed
103
+ expect(document.querySelector('[data-kt-alert-overlay]')).toBeNull();
104
+ });
105
+ });