@keenthemes/ktui 1.2.0 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (348) hide show
  1. package/dist/ktui.js +8355 -5213
  2. package/dist/ktui.min.js +1 -1
  3. package/dist/ktui.min.js.map +1 -1
  4. package/dist/styles.css +24 -1
  5. package/lib/cjs/components/carousel/carousel.d.ts +102 -0
  6. package/lib/cjs/components/carousel/carousel.d.ts.map +1 -0
  7. package/lib/cjs/components/carousel/carousel.js +769 -0
  8. package/lib/cjs/components/carousel/carousel.js.map +1 -0
  9. package/lib/cjs/components/carousel/index.d.ts +7 -0
  10. package/lib/cjs/components/carousel/index.d.ts.map +1 -0
  11. package/lib/cjs/components/carousel/index.js +10 -0
  12. package/lib/cjs/components/carousel/index.js.map +1 -0
  13. package/lib/cjs/components/carousel/types.d.ts +36 -0
  14. package/lib/cjs/components/carousel/types.d.ts.map +1 -0
  15. package/lib/cjs/components/carousel/types.js +7 -0
  16. package/lib/cjs/components/carousel/types.js.map +1 -0
  17. package/lib/cjs/components/clipboard/clipboard.d.ts +37 -0
  18. package/lib/cjs/components/clipboard/clipboard.d.ts.map +1 -0
  19. package/lib/cjs/components/clipboard/clipboard.js +402 -0
  20. package/lib/cjs/components/clipboard/clipboard.js.map +1 -0
  21. package/lib/cjs/components/clipboard/index.d.ts +3 -0
  22. package/lib/cjs/components/clipboard/index.d.ts.map +1 -0
  23. package/lib/cjs/components/clipboard/index.js +6 -0
  24. package/lib/cjs/components/clipboard/index.js.map +1 -0
  25. package/lib/cjs/components/clipboard/types.d.ts +44 -0
  26. package/lib/cjs/components/clipboard/types.d.ts.map +1 -0
  27. package/lib/cjs/components/clipboard/types.js +7 -0
  28. package/lib/cjs/components/clipboard/types.js.map +1 -0
  29. package/lib/cjs/components/component.d.ts +3 -3
  30. package/lib/cjs/components/component.d.ts.map +1 -1
  31. package/lib/cjs/components/component.js +9 -1
  32. package/lib/cjs/components/component.js.map +1 -1
  33. package/lib/cjs/components/datatable/datatable-checkbox.d.ts +1 -1
  34. package/lib/cjs/components/datatable/datatable-checkbox.d.ts.map +1 -1
  35. package/lib/cjs/components/datatable/datatable-checkbox.js +1 -1
  36. package/lib/cjs/components/datatable/datatable-checkbox.js.map +1 -1
  37. package/lib/cjs/components/datatable/datatable-sort.d.ts +1 -1
  38. package/lib/cjs/components/datatable/datatable-sort.d.ts.map +1 -1
  39. package/lib/cjs/components/datatable/datatable-sort.js.map +1 -1
  40. package/lib/cjs/components/datatable/datatable.d.ts +2 -0
  41. package/lib/cjs/components/datatable/datatable.d.ts.map +1 -1
  42. package/lib/cjs/components/datatable/datatable.js +29 -16
  43. package/lib/cjs/components/datatable/datatable.js.map +1 -1
  44. package/lib/cjs/components/datatable/types.d.ts +2 -1
  45. package/lib/cjs/components/datatable/types.d.ts.map +1 -1
  46. package/lib/cjs/components/drawer/drawer.d.ts.map +1 -1
  47. package/lib/cjs/components/drawer/drawer.js +3 -16
  48. package/lib/cjs/components/drawer/drawer.js.map +1 -1
  49. package/lib/cjs/components/dropdown/dropdown.d.ts +1 -1
  50. package/lib/cjs/components/dropdown/dropdown.d.ts.map +1 -1
  51. package/lib/cjs/components/dropdown/dropdown.js +2 -3
  52. package/lib/cjs/components/dropdown/dropdown.js.map +1 -1
  53. package/lib/cjs/components/pin-input/index.d.ts +3 -0
  54. package/lib/cjs/components/pin-input/index.d.ts.map +1 -0
  55. package/lib/cjs/components/pin-input/index.js +6 -0
  56. package/lib/cjs/components/pin-input/index.js.map +1 -0
  57. package/lib/cjs/components/pin-input/pin-input.d.ts +56 -0
  58. package/lib/cjs/components/pin-input/pin-input.d.ts.map +1 -0
  59. package/lib/cjs/components/pin-input/pin-input.js +455 -0
  60. package/lib/cjs/components/pin-input/pin-input.js.map +1 -0
  61. package/lib/cjs/components/pin-input/types.d.ts +41 -0
  62. package/lib/cjs/components/pin-input/types.d.ts.map +1 -0
  63. package/lib/cjs/components/pin-input/types.js +6 -0
  64. package/lib/cjs/components/pin-input/types.js.map +1 -0
  65. package/lib/cjs/components/range-slider/index.d.ts +7 -0
  66. package/lib/cjs/components/range-slider/index.d.ts.map +1 -0
  67. package/lib/cjs/components/range-slider/index.js +10 -0
  68. package/lib/cjs/components/range-slider/index.js.map +1 -0
  69. package/lib/cjs/components/range-slider/range-slider.d.ts +42 -0
  70. package/lib/cjs/components/range-slider/range-slider.d.ts.map +1 -0
  71. package/lib/cjs/components/range-slider/range-slider.js +254 -0
  72. package/lib/cjs/components/range-slider/range-slider.js.map +1 -0
  73. package/lib/cjs/components/range-slider/types.d.ts +33 -0
  74. package/lib/cjs/components/range-slider/types.d.ts.map +1 -0
  75. package/lib/cjs/components/range-slider/types.js +7 -0
  76. package/lib/cjs/components/range-slider/types.js.map +1 -0
  77. package/lib/cjs/components/rating/rating.d.ts.map +1 -1
  78. package/lib/cjs/components/rating/rating.js +8 -3
  79. package/lib/cjs/components/rating/rating.js.map +1 -1
  80. package/lib/cjs/components/repeater/repeater.d.ts.map +1 -1
  81. package/lib/cjs/components/repeater/repeater.js +3 -2
  82. package/lib/cjs/components/repeater/repeater.js.map +1 -1
  83. package/lib/cjs/components/select/combobox.d.ts.map +1 -1
  84. package/lib/cjs/components/select/combobox.js +25 -15
  85. package/lib/cjs/components/select/combobox.js.map +1 -1
  86. package/lib/cjs/components/select/config.d.ts +2 -2
  87. package/lib/cjs/components/select/config.d.ts.map +1 -1
  88. package/lib/cjs/components/select/config.js +10 -9
  89. package/lib/cjs/components/select/config.js.map +1 -1
  90. package/lib/cjs/components/select/dropdown.js.map +1 -1
  91. package/lib/cjs/components/select/option.d.ts +2 -1
  92. package/lib/cjs/components/select/option.d.ts.map +1 -1
  93. package/lib/cjs/components/select/option.js +9 -3
  94. package/lib/cjs/components/select/option.js.map +1 -1
  95. package/lib/cjs/components/select/remote.d.ts +1 -0
  96. package/lib/cjs/components/select/remote.d.ts.map +1 -1
  97. package/lib/cjs/components/select/remote.js +21 -14
  98. package/lib/cjs/components/select/remote.js.map +1 -1
  99. package/lib/cjs/components/select/search.d.ts +1 -1
  100. package/lib/cjs/components/select/search.d.ts.map +1 -1
  101. package/lib/cjs/components/select/search.js +34 -25
  102. package/lib/cjs/components/select/search.js.map +1 -1
  103. package/lib/cjs/components/select/select.d.ts +5 -3
  104. package/lib/cjs/components/select/select.d.ts.map +1 -1
  105. package/lib/cjs/components/select/select.js +31 -31
  106. package/lib/cjs/components/select/select.js.map +1 -1
  107. package/lib/cjs/components/select/tags.d.ts.map +1 -1
  108. package/lib/cjs/components/select/tags.js +22 -13
  109. package/lib/cjs/components/select/tags.js.map +1 -1
  110. package/lib/cjs/components/select/templates.d.ts.map +1 -1
  111. package/lib/cjs/components/select/templates.js +4 -4
  112. package/lib/cjs/components/select/templates.js.map +1 -1
  113. package/lib/cjs/components/select/types.d.ts +1 -1
  114. package/lib/cjs/components/select/types.d.ts.map +1 -1
  115. package/lib/cjs/components/select/utils.d.ts +4 -4
  116. package/lib/cjs/components/select/utils.d.ts.map +1 -1
  117. package/lib/cjs/components/select/utils.js +5 -4
  118. package/lib/cjs/components/select/utils.js.map +1 -1
  119. package/lib/cjs/components/sticky/sticky.d.ts +1 -1
  120. package/lib/cjs/components/sticky/sticky.d.ts.map +1 -1
  121. package/lib/cjs/components/sticky/sticky.js +16 -14
  122. package/lib/cjs/components/sticky/sticky.js.map +1 -1
  123. package/lib/cjs/components/toast/toast.d.ts.map +1 -1
  124. package/lib/cjs/components/toast/toast.js +17 -9
  125. package/lib/cjs/components/toast/toast.js.map +1 -1
  126. package/lib/cjs/components/toast/types.d.ts +3 -0
  127. package/lib/cjs/components/toast/types.d.ts.map +1 -1
  128. package/lib/cjs/components/toggle-password/toggle-password.d.ts.map +1 -1
  129. package/lib/cjs/components/toggle-password/toggle-password.js.map +1 -1
  130. package/lib/cjs/helpers/dom.d.ts +4 -4
  131. package/lib/cjs/helpers/dom.d.ts.map +1 -1
  132. package/lib/cjs/helpers/dom.js +8 -10
  133. package/lib/cjs/helpers/dom.js.map +1 -1
  134. package/lib/cjs/helpers/event-handler.d.ts +1 -1
  135. package/lib/cjs/helpers/event-handler.d.ts.map +1 -1
  136. package/lib/cjs/helpers/event-handler.js +3 -1
  137. package/lib/cjs/helpers/event-handler.js.map +1 -1
  138. package/lib/cjs/helpers/utils.d.ts +1 -1
  139. package/lib/cjs/helpers/utils.d.ts.map +1 -1
  140. package/lib/cjs/helpers/utils.js +4 -1
  141. package/lib/cjs/helpers/utils.js.map +1 -1
  142. package/lib/cjs/index.d.ts +16 -0
  143. package/lib/cjs/index.d.ts.map +1 -1
  144. package/lib/cjs/index.js +17 -1
  145. package/lib/cjs/index.js.map +1 -1
  146. package/lib/cjs/types.d.ts +1 -1
  147. package/lib/cjs/types.d.ts.map +1 -1
  148. package/lib/esm/components/carousel/carousel.d.ts +102 -0
  149. package/lib/esm/components/carousel/carousel.d.ts.map +1 -0
  150. package/lib/esm/components/carousel/carousel.js +766 -0
  151. package/lib/esm/components/carousel/carousel.js.map +1 -0
  152. package/lib/esm/components/carousel/index.d.ts +7 -0
  153. package/lib/esm/components/carousel/index.d.ts.map +1 -0
  154. package/lib/esm/components/carousel/index.js +6 -0
  155. package/lib/esm/components/carousel/index.js.map +1 -0
  156. package/lib/esm/components/carousel/types.d.ts +36 -0
  157. package/lib/esm/components/carousel/types.d.ts.map +1 -0
  158. package/lib/esm/components/carousel/types.js +6 -0
  159. package/lib/esm/components/carousel/types.js.map +1 -0
  160. package/lib/esm/components/clipboard/clipboard.d.ts +37 -0
  161. package/lib/esm/components/clipboard/clipboard.d.ts.map +1 -0
  162. package/lib/esm/components/clipboard/clipboard.js +399 -0
  163. package/lib/esm/components/clipboard/clipboard.js.map +1 -0
  164. package/lib/esm/components/clipboard/index.d.ts +3 -0
  165. package/lib/esm/components/clipboard/index.d.ts.map +1 -0
  166. package/lib/esm/components/clipboard/index.js +2 -0
  167. package/lib/esm/components/clipboard/index.js.map +1 -0
  168. package/lib/esm/components/clipboard/types.d.ts +44 -0
  169. package/lib/esm/components/clipboard/types.d.ts.map +1 -0
  170. package/lib/esm/components/clipboard/types.js +6 -0
  171. package/lib/esm/components/clipboard/types.js.map +1 -0
  172. package/lib/esm/components/component.d.ts +3 -3
  173. package/lib/esm/components/component.d.ts.map +1 -1
  174. package/lib/esm/components/component.js +9 -1
  175. package/lib/esm/components/component.js.map +1 -1
  176. package/lib/esm/components/datatable/datatable-checkbox.d.ts +1 -1
  177. package/lib/esm/components/datatable/datatable-checkbox.d.ts.map +1 -1
  178. package/lib/esm/components/datatable/datatable-checkbox.js +1 -1
  179. package/lib/esm/components/datatable/datatable-checkbox.js.map +1 -1
  180. package/lib/esm/components/datatable/datatable-sort.d.ts +1 -1
  181. package/lib/esm/components/datatable/datatable-sort.d.ts.map +1 -1
  182. package/lib/esm/components/datatable/datatable-sort.js.map +1 -1
  183. package/lib/esm/components/datatable/datatable.d.ts +2 -0
  184. package/lib/esm/components/datatable/datatable.d.ts.map +1 -1
  185. package/lib/esm/components/datatable/datatable.js +29 -16
  186. package/lib/esm/components/datatable/datatable.js.map +1 -1
  187. package/lib/esm/components/datatable/types.d.ts +2 -1
  188. package/lib/esm/components/datatable/types.d.ts.map +1 -1
  189. package/lib/esm/components/drawer/drawer.d.ts.map +1 -1
  190. package/lib/esm/components/drawer/drawer.js +3 -16
  191. package/lib/esm/components/drawer/drawer.js.map +1 -1
  192. package/lib/esm/components/dropdown/dropdown.d.ts +1 -1
  193. package/lib/esm/components/dropdown/dropdown.d.ts.map +1 -1
  194. package/lib/esm/components/dropdown/dropdown.js +2 -3
  195. package/lib/esm/components/dropdown/dropdown.js.map +1 -1
  196. package/lib/esm/components/pin-input/index.d.ts +3 -0
  197. package/lib/esm/components/pin-input/index.d.ts.map +1 -0
  198. package/lib/esm/components/pin-input/index.js +2 -0
  199. package/lib/esm/components/pin-input/index.js.map +1 -0
  200. package/lib/esm/components/pin-input/pin-input.d.ts +56 -0
  201. package/lib/esm/components/pin-input/pin-input.d.ts.map +1 -0
  202. package/lib/esm/components/pin-input/pin-input.js +452 -0
  203. package/lib/esm/components/pin-input/pin-input.js.map +1 -0
  204. package/lib/esm/components/pin-input/types.d.ts +41 -0
  205. package/lib/esm/components/pin-input/types.d.ts.map +1 -0
  206. package/lib/esm/components/pin-input/types.js +5 -0
  207. package/lib/esm/components/pin-input/types.js.map +1 -0
  208. package/lib/esm/components/range-slider/index.d.ts +7 -0
  209. package/lib/esm/components/range-slider/index.d.ts.map +1 -0
  210. package/lib/esm/components/range-slider/index.js +6 -0
  211. package/lib/esm/components/range-slider/index.js.map +1 -0
  212. package/lib/esm/components/range-slider/range-slider.d.ts +42 -0
  213. package/lib/esm/components/range-slider/range-slider.d.ts.map +1 -0
  214. package/lib/esm/components/range-slider/range-slider.js +251 -0
  215. package/lib/esm/components/range-slider/range-slider.js.map +1 -0
  216. package/lib/esm/components/range-slider/types.d.ts +33 -0
  217. package/lib/esm/components/range-slider/types.d.ts.map +1 -0
  218. package/lib/esm/components/range-slider/types.js +6 -0
  219. package/lib/esm/components/range-slider/types.js.map +1 -0
  220. package/lib/esm/components/rating/rating.d.ts.map +1 -1
  221. package/lib/esm/components/rating/rating.js +8 -3
  222. package/lib/esm/components/rating/rating.js.map +1 -1
  223. package/lib/esm/components/repeater/repeater.d.ts.map +1 -1
  224. package/lib/esm/components/repeater/repeater.js +3 -2
  225. package/lib/esm/components/repeater/repeater.js.map +1 -1
  226. package/lib/esm/components/select/combobox.d.ts.map +1 -1
  227. package/lib/esm/components/select/combobox.js +25 -15
  228. package/lib/esm/components/select/combobox.js.map +1 -1
  229. package/lib/esm/components/select/config.d.ts +2 -2
  230. package/lib/esm/components/select/config.d.ts.map +1 -1
  231. package/lib/esm/components/select/config.js +10 -9
  232. package/lib/esm/components/select/config.js.map +1 -1
  233. package/lib/esm/components/select/dropdown.js.map +1 -1
  234. package/lib/esm/components/select/option.d.ts +2 -1
  235. package/lib/esm/components/select/option.d.ts.map +1 -1
  236. package/lib/esm/components/select/option.js +9 -3
  237. package/lib/esm/components/select/option.js.map +1 -1
  238. package/lib/esm/components/select/remote.d.ts +1 -0
  239. package/lib/esm/components/select/remote.d.ts.map +1 -1
  240. package/lib/esm/components/select/remote.js +21 -14
  241. package/lib/esm/components/select/remote.js.map +1 -1
  242. package/lib/esm/components/select/search.d.ts +1 -1
  243. package/lib/esm/components/select/search.d.ts.map +1 -1
  244. package/lib/esm/components/select/search.js +34 -25
  245. package/lib/esm/components/select/search.js.map +1 -1
  246. package/lib/esm/components/select/select.d.ts +5 -3
  247. package/lib/esm/components/select/select.d.ts.map +1 -1
  248. package/lib/esm/components/select/select.js +31 -31
  249. package/lib/esm/components/select/select.js.map +1 -1
  250. package/lib/esm/components/select/tags.d.ts.map +1 -1
  251. package/lib/esm/components/select/tags.js +22 -13
  252. package/lib/esm/components/select/tags.js.map +1 -1
  253. package/lib/esm/components/select/templates.d.ts.map +1 -1
  254. package/lib/esm/components/select/templates.js +4 -4
  255. package/lib/esm/components/select/templates.js.map +1 -1
  256. package/lib/esm/components/select/types.d.ts +1 -1
  257. package/lib/esm/components/select/types.d.ts.map +1 -1
  258. package/lib/esm/components/select/utils.d.ts +4 -4
  259. package/lib/esm/components/select/utils.d.ts.map +1 -1
  260. package/lib/esm/components/select/utils.js +5 -4
  261. package/lib/esm/components/select/utils.js.map +1 -1
  262. package/lib/esm/components/sticky/sticky.d.ts +1 -1
  263. package/lib/esm/components/sticky/sticky.d.ts.map +1 -1
  264. package/lib/esm/components/sticky/sticky.js +16 -14
  265. package/lib/esm/components/sticky/sticky.js.map +1 -1
  266. package/lib/esm/components/toast/toast.d.ts.map +1 -1
  267. package/lib/esm/components/toast/toast.js +17 -9
  268. package/lib/esm/components/toast/toast.js.map +1 -1
  269. package/lib/esm/components/toast/types.d.ts +3 -0
  270. package/lib/esm/components/toast/types.d.ts.map +1 -1
  271. package/lib/esm/components/toggle-password/toggle-password.d.ts.map +1 -1
  272. package/lib/esm/components/toggle-password/toggle-password.js.map +1 -1
  273. package/lib/esm/helpers/dom.d.ts +4 -4
  274. package/lib/esm/helpers/dom.d.ts.map +1 -1
  275. package/lib/esm/helpers/dom.js +8 -10
  276. package/lib/esm/helpers/dom.js.map +1 -1
  277. package/lib/esm/helpers/event-handler.d.ts +1 -1
  278. package/lib/esm/helpers/event-handler.d.ts.map +1 -1
  279. package/lib/esm/helpers/event-handler.js +3 -1
  280. package/lib/esm/helpers/event-handler.js.map +1 -1
  281. package/lib/esm/helpers/utils.d.ts +1 -1
  282. package/lib/esm/helpers/utils.d.ts.map +1 -1
  283. package/lib/esm/helpers/utils.js +4 -1
  284. package/lib/esm/helpers/utils.js.map +1 -1
  285. package/lib/esm/index.d.ts +16 -0
  286. package/lib/esm/index.d.ts.map +1 -1
  287. package/lib/esm/index.js +12 -0
  288. package/lib/esm/index.js.map +1 -1
  289. package/lib/esm/types.d.ts +1 -1
  290. package/lib/esm/types.d.ts.map +1 -1
  291. package/package.json +5 -3
  292. package/src/components/carousel/__tests__/carousel.test.ts +326 -0
  293. package/src/components/carousel/carousel.css +42 -0
  294. package/src/components/carousel/carousel.ts +847 -0
  295. package/src/components/carousel/index.ts +11 -0
  296. package/src/components/carousel/types.ts +38 -0
  297. package/src/components/clipboard/__tests__/clipboard.test.ts +438 -0
  298. package/src/components/clipboard/clipboard.ts +416 -0
  299. package/src/components/clipboard/index.ts +2 -0
  300. package/src/components/clipboard/types.ts +51 -0
  301. package/src/components/component.ts +15 -5
  302. package/src/components/datatable/__tests__/currency-sort.test.ts +6 -13
  303. package/src/components/datatable/__tests__/multi-row-headers.test.ts +2 -2
  304. package/src/components/datatable/__tests__/pagination-reset.test.ts +7 -4
  305. package/src/components/datatable/__tests__/race-conditions.test.ts +11 -14
  306. package/src/components/datatable/__tests__/setup.ts +1 -1
  307. package/src/components/datatable/datatable-checkbox.ts +6 -4
  308. package/src/components/datatable/datatable-sort.ts +27 -7
  309. package/src/components/datatable/datatable.ts +67 -42
  310. package/src/components/datatable/types.ts +3 -1
  311. package/src/components/drawer/drawer.ts +3 -18
  312. package/src/components/dropdown/dropdown.ts +2 -3
  313. package/src/components/pin-input/__tests__/pin-input.test.ts +928 -0
  314. package/src/components/pin-input/index.ts +6 -0
  315. package/src/components/pin-input/pin-input.ts +499 -0
  316. package/src/components/pin-input/types.ts +45 -0
  317. package/src/components/range-slider/__tests__/range-slider.test.ts +659 -0
  318. package/src/components/range-slider/index.ts +11 -0
  319. package/src/components/range-slider/range-slider.ts +276 -0
  320. package/src/components/range-slider/types.ts +36 -0
  321. package/src/components/rating/__tests__/rating.test.ts +11 -4
  322. package/src/components/rating/rating.ts +22 -12
  323. package/src/components/repeater/__tests__/repeater.test.ts +24 -11
  324. package/src/components/repeater/repeater.ts +5 -3
  325. package/src/components/select/__tests__/ux-behaviors.test.ts +25 -6
  326. package/src/components/select/combobox.ts +23 -16
  327. package/src/components/select/config.ts +15 -14
  328. package/src/components/select/dropdown.ts +1 -1
  329. package/src/components/select/option.ts +14 -4
  330. package/src/components/select/remote.ts +68 -56
  331. package/src/components/select/search.ts +30 -27
  332. package/src/components/select/select.ts +41 -37
  333. package/src/components/select/tags.ts +14 -8
  334. package/src/components/select/templates.ts +11 -6
  335. package/src/components/select/types.ts +1 -1
  336. package/src/components/select/utils.ts +12 -10
  337. package/src/components/sticky/__tests__/sticky.test.ts +10 -3
  338. package/src/components/sticky/sticky.ts +16 -26
  339. package/src/components/sticky/types.ts +3 -3
  340. package/src/components/toast/toast.ts +34 -21
  341. package/src/components/toast/types.ts +5 -1
  342. package/src/components/toggle-password/toggle-password.ts +0 -1
  343. package/src/helpers/dom.ts +14 -17
  344. package/src/helpers/event-handler.ts +5 -6
  345. package/src/helpers/utils.ts +5 -2
  346. package/src/index.ts +35 -0
  347. package/src/types.ts +1 -1
  348. package/styles.css +1 -0
@@ -0,0 +1,416 @@
1
+ /**
2
+ * KTUI - Free & Open-Source Tailwind UI Components by Keenthemes
3
+ * Copyright 2025 by Keenthemes Inc
4
+ */
5
+
6
+ import KTComponent from '../component';
7
+ import KTData from '../../helpers/data';
8
+ import KTDom from '../../helpers/dom';
9
+ import {
10
+ KTClipboardActionType,
11
+ KTClipboardConfigInterface,
12
+ KTClipboardInterface,
13
+ } from './types';
14
+
15
+ type KTClipboardEventPayload = {
16
+ action: KTClipboardActionType;
17
+ text: string | null;
18
+ target: string | null;
19
+ error?: string;
20
+ };
21
+
22
+ declare global {
23
+ interface Window {
24
+ KTClipboard: typeof KTClipboard;
25
+ }
26
+ }
27
+
28
+ export class KTClipboard extends KTComponent implements KTClipboardInterface {
29
+ protected override _name: string = 'clipboard';
30
+
31
+ protected override _defaultConfig: KTClipboardConfigInterface = {
32
+ target: '',
33
+ text: '',
34
+ action: 'copy',
35
+ copiedClass: '',
36
+ successEvent: 'kt.clipboard.success',
37
+ errorEvent: 'kt.clipboard.error',
38
+ };
39
+
40
+ protected override _config: KTClipboardConfigInterface = this
41
+ ._defaultConfig as KTClipboardConfigInterface;
42
+
43
+ private _activateHandler: ((event: Event) => void) | null = null;
44
+
45
+ constructor(
46
+ element: HTMLElement,
47
+ config: KTClipboardConfigInterface | null = null,
48
+ ) {
49
+ super();
50
+
51
+ // Ensure we don't double bind handlers on the same trigger.
52
+ if (this._shouldSkipInit(element)) {
53
+ return;
54
+ }
55
+
56
+ this._init(element);
57
+ this._buildConfig(config);
58
+
59
+ if (!this._element) return;
60
+
61
+ this._activateHandler = this._handleActivate.bind(this);
62
+ this._element.addEventListener('click', this._activateHandler);
63
+ }
64
+
65
+ private _getSuccessEventName(): string {
66
+ const eventName = this._getOption('successEvent');
67
+ return typeof eventName === 'string' && eventName.length > 0
68
+ ? eventName
69
+ : 'kt.clipboard.success';
70
+ }
71
+
72
+ private _getErrorEventName(): string {
73
+ const eventName = this._getOption('errorEvent');
74
+ return typeof eventName === 'string' && eventName.length > 0
75
+ ? eventName
76
+ : 'kt.clipboard.error';
77
+ }
78
+
79
+ private _getAction(): KTClipboardActionType {
80
+ const action = this._getOption('action');
81
+ return action === 'cut' ? 'cut' : 'copy';
82
+ }
83
+
84
+ private _getTrimmedString(optionValue: unknown): string {
85
+ return typeof optionValue === 'string' ? optionValue.trim() : '';
86
+ }
87
+
88
+ private _getPredefinedText(): string {
89
+ const text = this._getOption('text');
90
+ return this._getTrimmedString(text);
91
+ }
92
+
93
+ private _getTargetSelector(): string {
94
+ const target = this._getOption('target');
95
+ return this._getTrimmedString(target);
96
+ }
97
+
98
+ private _getCopiedClass(): string {
99
+ const copiedClass = this._getOption('copiedClass');
100
+ return this._getTrimmedString(copiedClass);
101
+ }
102
+
103
+ private _setCopiedClass(shouldSet: boolean): void {
104
+ const copiedClass = this._getCopiedClass();
105
+ if (!copiedClass || !this._element) return;
106
+
107
+ // Keep deterministic behavior: remove any previous state before toggling.
108
+ KTDom.removeClass(this._element, copiedClass);
109
+ if (shouldSet) {
110
+ KTDom.addClass(this._element, copiedClass);
111
+ }
112
+ }
113
+
114
+ private _isInputLike(element: HTMLElement): boolean {
115
+ return element.tagName === 'INPUT' || element.tagName === 'TEXTAREA';
116
+ }
117
+
118
+ private _readTargetValue(target: HTMLElement): string {
119
+ if (this._isInputLike(target)) {
120
+ return (target as HTMLInputElement | HTMLTextAreaElement).value ?? '';
121
+ }
122
+
123
+ return target.textContent ?? '';
124
+ }
125
+
126
+ private _execCommandCopy(text: string): boolean {
127
+ const textarea = document.createElement('textarea');
128
+ textarea.value = text;
129
+
130
+ // Avoid scrolling to bottom on iOS/Safari and keep it out of layout.
131
+ textarea.style.position = 'fixed';
132
+ textarea.style.top = '0';
133
+ textarea.style.left = '0';
134
+ textarea.style.opacity = '0';
135
+ textarea.style.pointerEvents = 'none';
136
+
137
+ document.body.appendChild(textarea);
138
+ textarea.focus();
139
+ textarea.select();
140
+ // Some browsers require explicit range selection.
141
+ textarea.setSelectionRange(0, textarea.value.length);
142
+
143
+ try {
144
+ return document.execCommand('copy');
145
+ } catch {
146
+ return false;
147
+ } finally {
148
+ textarea.remove();
149
+ }
150
+ }
151
+
152
+ private async _writeText(text: string): Promise<boolean> {
153
+ // Native Clipboard API (requires secure context).
154
+ const clipboard =
155
+ typeof navigator !== 'undefined' ? navigator.clipboard : null;
156
+ const writeText =
157
+ clipboard && typeof clipboard.writeText === 'function'
158
+ ? clipboard.writeText.bind(clipboard)
159
+ : null;
160
+
161
+ if (writeText) {
162
+ await writeText(text);
163
+ return true;
164
+ }
165
+
166
+ const ok = this._execCommandCopy(text);
167
+ if (!ok) {
168
+ throw new Error('Clipboard copy failed.');
169
+ }
170
+
171
+ return true;
172
+ }
173
+
174
+ private async _handleActivate(event: Event): Promise<void> {
175
+ event.preventDefault();
176
+
177
+ const action = this._getAction();
178
+ const successEventName = this._getSuccessEventName();
179
+ const errorEventName = this._getErrorEventName();
180
+ const textFromConfig = this._getPredefinedText();
181
+ const targetSelector = this._getTargetSelector();
182
+ const hasPredefinedText = Boolean(
183
+ this._element?.hasAttribute('data-kt-clipboard-text'),
184
+ );
185
+
186
+ // Deterministic precedence:
187
+ // - If `data-kt-clipboard-text` attribute is present, it wins over target.
188
+ if (hasPredefinedText) {
189
+ let targetElForCut: HTMLElement | null = null;
190
+
191
+ // `cut` requires an editable target (input/textarea) even when predefined text is used.
192
+ if (action === 'cut') {
193
+ if (!targetSelector) {
194
+ this._setCopiedClass(false);
195
+
196
+ const payload: KTClipboardEventPayload = {
197
+ action,
198
+ text: null,
199
+ target: null,
200
+ error:
201
+ 'Cut action requires data-kt-clipboard-target pointing to an input/textarea.',
202
+ };
203
+
204
+ this._fireEvent(errorEventName, payload);
205
+ this._dispatchEvent(errorEventName, payload);
206
+ return;
207
+ }
208
+
209
+ targetElForCut = KTDom.getElement(targetSelector) as HTMLElement | null;
210
+
211
+ if (!targetElForCut || !this._isInputLike(targetElForCut)) {
212
+ this._setCopiedClass(false);
213
+
214
+ const payload: KTClipboardEventPayload = {
215
+ action,
216
+ text: null,
217
+ target: targetSelector,
218
+ error: 'Cut action is only supported for input/textarea targets.',
219
+ };
220
+
221
+ this._fireEvent(errorEventName, payload);
222
+ this._dispatchEvent(errorEventName, payload);
223
+ return;
224
+ }
225
+ }
226
+
227
+ // Treat empty/whitespace-only predefined text as invalid.
228
+ if (!textFromConfig) {
229
+ this._setCopiedClass(false);
230
+
231
+ const payload: KTClipboardEventPayload = {
232
+ action,
233
+ text: null,
234
+ target: targetSelector || null,
235
+ error: 'Predefined clipboard text is empty.',
236
+ };
237
+
238
+ this._fireEvent(errorEventName, payload);
239
+ this._dispatchEvent(errorEventName, payload);
240
+ return;
241
+ }
242
+
243
+ try {
244
+ await this._writeText(textFromConfig);
245
+
246
+ // For `cut`, clear the editable target after successful clipboard write.
247
+ if (action === 'cut' && targetElForCut) {
248
+ (targetElForCut as HTMLInputElement | HTMLTextAreaElement).value = '';
249
+ targetElForCut.dispatchEvent(new Event('input', { bubbles: true }));
250
+ }
251
+
252
+ this._setCopiedClass(true);
253
+
254
+ const payload: KTClipboardEventPayload = {
255
+ action,
256
+ text: textFromConfig,
257
+ target: targetSelector || null,
258
+ };
259
+
260
+ this._fireEvent(successEventName, payload);
261
+ this._dispatchEvent(successEventName, payload);
262
+ } catch (error) {
263
+ this._setCopiedClass(false);
264
+
265
+ const payload: KTClipboardEventPayload = {
266
+ action,
267
+ text: textFromConfig,
268
+ target: targetSelector || null,
269
+ error:
270
+ error instanceof Error ? error.message : String(error ?? 'Unknown'),
271
+ };
272
+
273
+ this._fireEvent(errorEventName, payload);
274
+ this._dispatchEvent(errorEventName, payload);
275
+ }
276
+
277
+ return;
278
+ }
279
+
280
+ // No usable predefined text; copy from target.
281
+ if (!targetSelector) {
282
+ this._setCopiedClass(false);
283
+
284
+ const payload: KTClipboardEventPayload = {
285
+ action,
286
+ text: null,
287
+ target: null,
288
+ error:
289
+ 'Missing clipboard source (provide data-kt-clipboard-text or data-kt-clipboard-target).',
290
+ };
291
+
292
+ this._fireEvent(errorEventName, payload);
293
+ this._dispatchEvent(errorEventName, payload);
294
+ return;
295
+ }
296
+
297
+ const targetEl = KTDom.getElement(targetSelector) as HTMLElement | null;
298
+ if (!targetEl) {
299
+ this._setCopiedClass(false);
300
+
301
+ const payload: KTClipboardEventPayload = {
302
+ action,
303
+ text: null,
304
+ target: targetSelector,
305
+ error: `Clipboard target not found: ${targetSelector}`,
306
+ };
307
+
308
+ this._fireEvent(errorEventName, payload);
309
+ this._dispatchEvent(errorEventName, payload);
310
+ return;
311
+ }
312
+
313
+ const value = this._readTargetValue(targetEl).trim();
314
+ if (!value) {
315
+ this._setCopiedClass(false);
316
+
317
+ const payload: KTClipboardEventPayload = {
318
+ action,
319
+ text: null,
320
+ target: targetSelector,
321
+ error: 'Target content is empty.',
322
+ };
323
+
324
+ this._fireEvent(errorEventName, payload);
325
+ this._dispatchEvent(errorEventName, payload);
326
+ return;
327
+ }
328
+
329
+ // Cut action: only allowed for input/textarea.
330
+ if (action === 'cut' && !this._isInputLike(targetEl)) {
331
+ this._setCopiedClass(false);
332
+
333
+ const payload: KTClipboardEventPayload = {
334
+ action,
335
+ text: null,
336
+ target: targetSelector,
337
+ error: 'Cut action is only supported for input/textarea targets.',
338
+ };
339
+
340
+ this._fireEvent(errorEventName, payload);
341
+ this._dispatchEvent(errorEventName, payload);
342
+ return;
343
+ }
344
+
345
+ try {
346
+ await this._writeText(value);
347
+ this._setCopiedClass(true);
348
+
349
+ if (action === 'cut') {
350
+ (targetEl as HTMLInputElement | HTMLTextAreaElement).value = '';
351
+ targetEl.dispatchEvent(new Event('input', { bubbles: true }));
352
+ }
353
+
354
+ const payload: KTClipboardEventPayload = {
355
+ action,
356
+ text: value,
357
+ target: targetSelector,
358
+ };
359
+
360
+ this._fireEvent(successEventName, payload);
361
+ this._dispatchEvent(successEventName, payload);
362
+ } catch (error) {
363
+ this._setCopiedClass(false);
364
+
365
+ const payload: KTClipboardEventPayload = {
366
+ action,
367
+ text: null,
368
+ target: targetSelector,
369
+ error:
370
+ error instanceof Error ? error.message : String(error ?? 'Unknown'),
371
+ };
372
+
373
+ this._fireEvent(errorEventName, payload);
374
+ this._dispatchEvent(errorEventName, payload);
375
+ }
376
+ }
377
+
378
+ public override dispose(): void {
379
+ if (this._element && this._activateHandler) {
380
+ this._element.removeEventListener('click', this._activateHandler);
381
+ }
382
+ this._activateHandler = null;
383
+ super.dispose();
384
+ }
385
+
386
+ public static getInstance(element: HTMLElement): KTClipboard | null {
387
+ if (!element) return null;
388
+ if (KTData.has(element, 'clipboard')) {
389
+ return KTData.get(element, 'clipboard') as KTClipboard;
390
+ }
391
+ return null;
392
+ }
393
+
394
+ public static getOrCreateInstance(
395
+ element: HTMLElement,
396
+ config?: KTClipboardConfigInterface,
397
+ ): KTClipboard {
398
+ return (
399
+ this.getInstance(element) || new KTClipboard(element, config ?? undefined)
400
+ );
401
+ }
402
+
403
+ public static createInstances(): void {
404
+ document.querySelectorAll('[data-kt-clipboard]').forEach((el) => {
405
+ new KTClipboard(el as HTMLElement);
406
+ });
407
+ }
408
+
409
+ public static init(): void {
410
+ KTClipboard.createInstances();
411
+ }
412
+ }
413
+
414
+ if (typeof window !== 'undefined') {
415
+ window.KTClipboard = KTClipboard;
416
+ }
@@ -0,0 +1,2 @@
1
+ export { KTClipboard } from './clipboard';
2
+ export type { KTClipboardConfigInterface, KTClipboardInterface } from './types';
@@ -0,0 +1,51 @@
1
+ /**
2
+ * KTUI - Free & Open-Source Tailwind UI Components by Keenthemes
3
+ * Copyright 2025 by Keenthemes Inc
4
+ */
5
+
6
+ export type KTClipboardActionType = 'copy' | 'cut';
7
+
8
+ export interface KTClipboardConfigInterface {
9
+ /**
10
+ * CSS selector for the element to read from when copying from target.
11
+ * For `input`/`textarea`, reads `.value`; for other elements, reads `.textContent`.
12
+ */
13
+ target?: string;
14
+
15
+ /**
16
+ * Static string to copy. Takes precedence over `target` when both are present.
17
+ */
18
+ text?: string;
19
+
20
+ /**
21
+ * Clipboard action to perform.
22
+ * - `copy` (default)
23
+ * - `cut` (only valid for `input`/`textarea` targets)
24
+ */
25
+ action?: KTClipboardActionType;
26
+
27
+ /**
28
+ * Optional class toggled on the trigger when copy/cut succeeds.
29
+ */
30
+ copiedClass?: string;
31
+
32
+ /**
33
+ * Optional DOM event name dispatched on success.
34
+ * Defaults to `kt.clipboard.success`.
35
+ */
36
+ successEvent?: string;
37
+
38
+ /**
39
+ * Optional DOM event name dispatched on failure.
40
+ * Defaults to `kt.clipboard.error`.
41
+ */
42
+ errorEvent?: string;
43
+ }
44
+
45
+ export interface KTClipboardInterface {
46
+ getOption(name: string): unknown;
47
+ getElement(): HTMLElement | null;
48
+ on(eventType: string, callback: CallableFunction): string;
49
+ off(eventType: string, eventId: string): void;
50
+ dispose(): void;
51
+ }
@@ -19,7 +19,7 @@ export default class KTComponent {
19
19
  protected _name: string;
20
20
  protected _defaultConfig: object;
21
21
  protected _config: object;
22
- protected _events: Map<string, Map<string, CallableFunction>>;
22
+ protected _events: Map<string, Map<string, CallableFunction>> = new Map();
23
23
  protected _uid: string | null = null;
24
24
  protected _element: HTMLElement | null = null;
25
25
 
@@ -67,7 +67,7 @@ export default class KTComponent {
67
67
 
68
68
  protected async _fireEvent(
69
69
  eventType: string,
70
- payload: object = null,
70
+ payload: object | null = null,
71
71
  ): Promise<void> {
72
72
  const callbacks = this._events.get(eventType);
73
73
 
@@ -86,7 +86,10 @@ export default class KTComponent {
86
86
  );
87
87
  }
88
88
 
89
- protected _dispatchEvent(eventType: string, payload: object = null): void {
89
+ protected _dispatchEvent(
90
+ eventType: string,
91
+ payload: object | null = null,
92
+ ): void {
90
93
  const event = new CustomEvent(eventType, {
91
94
  detail: { payload },
92
95
  bubbles: true,
@@ -100,6 +103,9 @@ export default class KTComponent {
100
103
 
101
104
  protected _getOption(name: string): KTOptionType {
102
105
  const value = this._config[name as keyof object];
106
+ if (!this._element) {
107
+ return value as KTOptionType;
108
+ }
103
109
  const reponsiveValue = KTDom.getCssProp(
104
110
  this._element,
105
111
  `--kt-${this._name}-${KTUtils.camelReverseCase(name)}`,
@@ -163,7 +169,11 @@ export default class KTComponent {
163
169
  this._events.set(eventType, new Map());
164
170
  }
165
171
 
166
- this._events.get(eventType).set(eventId, callback);
172
+ const eventMap = this._events.get(eventType);
173
+ if (!eventMap) {
174
+ return eventId;
175
+ }
176
+ eventMap.set(eventId, callback);
167
177
 
168
178
  return eventId;
169
179
  }
@@ -176,7 +186,7 @@ export default class KTComponent {
176
186
  return this._getOption(name as keyof object);
177
187
  }
178
188
 
179
- public getElement(): HTMLElement {
189
+ public getElement(): HTMLElement | null {
180
190
  if (!this._element) return null;
181
191
  return this._element;
182
192
  }
@@ -8,6 +8,7 @@
8
8
 
9
9
  import { describe, it, expect, beforeEach, vi } from 'vitest';
10
10
  import { createSortHandler } from '../datatable-sort';
11
+ import { KTDataTableConfigInterface } from '../types';
11
12
 
12
13
  describe('KTDataTable - Currency/numeric sort', () => {
13
14
  let thead: HTMLTableSectionElement;
@@ -29,7 +30,7 @@ describe('KTDataTable - Currency/numeric sort', () => {
29
30
  },
30
31
  };
31
32
  const handler = createSortHandler(
32
- config as any,
33
+ config as KTDataTableConfigInterface,
33
34
  thead,
34
35
  () => ({ sortField: null, sortOrder: '' }),
35
36
  noop,
@@ -58,7 +59,7 @@ describe('KTDataTable - Currency/numeric sort', () => {
58
59
  },
59
60
  };
60
61
  const handler = createSortHandler(
61
- config as any,
62
+ config as KTDataTableConfigInterface,
62
63
  thead,
63
64
  () => ({ sortField: null, sortOrder: '' }),
64
65
  noop,
@@ -67,11 +68,7 @@ describe('KTDataTable - Currency/numeric sort', () => {
67
68
  noop,
68
69
  );
69
70
 
70
- const data = [
71
- { price: '£5' },
72
- { price: '£20' },
73
- { price: '£123' },
74
- ];
71
+ const data = [{ price: '£5' }, { price: '£20' }, { price: '£123' }];
75
72
  const sorted = handler.sortData(data, 'price', 'desc');
76
73
 
77
74
  const numericOrder = sorted.map((row) =>
@@ -83,7 +80,7 @@ describe('KTDataTable - Currency/numeric sort', () => {
83
80
  it('without sortType numeric, sorts lexicographically (e.g. £123 before £20)', () => {
84
81
  const config = { columns: {} };
85
82
  const handler = createSortHandler(
86
- config as any,
83
+ config as KTDataTableConfigInterface,
87
84
  thead,
88
85
  () => ({ sortField: null, sortOrder: '' }),
89
86
  noop,
@@ -92,11 +89,7 @@ describe('KTDataTable - Currency/numeric sort', () => {
92
89
  noop,
93
90
  );
94
91
 
95
- const data = [
96
- { price: '£123' },
97
- { price: '£20' },
98
- { price: '£5' },
99
- ];
92
+ const data = [{ price: '£123' }, { price: '£20' }, { price: '£5' }];
100
93
  const sorted = handler.sortData(data, 'price', 'asc');
101
94
 
102
95
  // String sort: "£123" < "£20" < "£5" (1 < 2 < 5)
@@ -89,7 +89,7 @@ describe('KTDataTable - Multi-row header column count', () => {
89
89
 
90
90
  it('should render exactly 17 columns when thead has multi-row headers and no data-kt-datatable-column', async () => {
91
91
  createMultiRowHeaderTable(2);
92
- const datatable = new KTDataTable(container, { stateSave: false });
92
+ new KTDataTable(container, { stateSave: false });
93
93
  await vi.runAllTimersAsync();
94
94
 
95
95
  const tbody = tableElement.tBodies[0];
@@ -107,7 +107,7 @@ describe('KTDataTable - Multi-row header column count', () => {
107
107
  createMultiRowHeaderTable(0);
108
108
  const tbody = tableElement.querySelector('tbody');
109
109
  expect(tbody).toBeDefined();
110
- const datatable = new KTDataTable(container, { stateSave: false });
110
+ new KTDataTable(container, { stateSave: false });
111
111
  await vi.runAllTimersAsync();
112
112
 
113
113
  const noticeRow = tableElement.tBodies[0].querySelector('tr');
@@ -13,7 +13,7 @@ import { KTDataTableColumnFilterInterface } from '../types';
13
13
  describe('KTDataTable - Pagination Reset', () => {
14
14
  let container: HTMLElement;
15
15
  let tableElement: HTMLTableElement;
16
- let datatable: KTDataTable<any>;
16
+ let datatable: KTDataTable<Record<string, unknown>>;
17
17
 
18
18
  /**
19
19
  * Helper: Create a mock datatable with sample data
@@ -177,13 +177,16 @@ describe('KTDataTable - Pagination Reset', () => {
177
177
  // Provide custom search callback that handles objects
178
178
  search: {
179
179
  delay: 500,
180
- callback: (data: any[], search: string | object) => {
180
+ callback: (
181
+ data: Record<string, unknown>[],
182
+ search: string | object,
183
+ ) => {
181
184
  if (!search) return data;
182
185
  // For object search, just return all data (simplified for test)
183
186
  if (typeof search === 'object') return data;
184
187
  // String search
185
- return data.filter((item: any) =>
186
- Object.values(item).some((value: any) =>
188
+ return data.filter((item: Record<string, unknown>) =>
189
+ Object.values(item).some((value: unknown) =>
187
190
  String(value)
188
191
  .toLowerCase()
189
192
  .includes((search as string).toLowerCase()),