@keenthemes/ktui 1.0.3

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 (426) hide show
  1. package/CONTRIBUTING.md +88 -0
  2. package/LICENSE.md +21 -0
  3. package/README.md +124 -0
  4. package/dist/ktui.js +19201 -0
  5. package/dist/ktui.min.js +2 -0
  6. package/dist/ktui.min.js.map +1 -0
  7. package/lib/cjs/components/accordion/accordion.js +168 -0
  8. package/lib/cjs/components/accordion/accordion.js.map +1 -0
  9. package/lib/cjs/components/accordion/index.js +6 -0
  10. package/lib/cjs/components/accordion/index.js.map +1 -0
  11. package/lib/cjs/components/accordion/types.js +3 -0
  12. package/lib/cjs/components/accordion/types.js.map +1 -0
  13. package/lib/cjs/components/collapse/collapse.js +169 -0
  14. package/lib/cjs/components/collapse/collapse.js.map +1 -0
  15. package/lib/cjs/components/collapse/index.js +6 -0
  16. package/lib/cjs/components/collapse/index.js.map +1 -0
  17. package/lib/cjs/components/collapse/types.js +3 -0
  18. package/lib/cjs/components/collapse/types.js.map +1 -0
  19. package/lib/cjs/components/component.js +135 -0
  20. package/lib/cjs/components/component.js.map +1 -0
  21. package/lib/cjs/components/config.js +26 -0
  22. package/lib/cjs/components/config.js.map +1 -0
  23. package/lib/cjs/components/config.umd.js +23 -0
  24. package/lib/cjs/components/config.umd.js.map +1 -0
  25. package/lib/cjs/components/constants.js +15 -0
  26. package/lib/cjs/components/constants.js.map +1 -0
  27. package/lib/cjs/components/datatable/datatable.js +1464 -0
  28. package/lib/cjs/components/datatable/datatable.js.map +1 -0
  29. package/lib/cjs/components/datatable/index.js +6 -0
  30. package/lib/cjs/components/datatable/index.js.map +1 -0
  31. package/lib/cjs/components/datatable/types.js +3 -0
  32. package/lib/cjs/components/datatable/types.js.map +1 -0
  33. package/lib/cjs/components/dismiss/dismiss.js +131 -0
  34. package/lib/cjs/components/dismiss/dismiss.js.map +1 -0
  35. package/lib/cjs/components/dismiss/index.js +6 -0
  36. package/lib/cjs/components/dismiss/index.js.map +1 -0
  37. package/lib/cjs/components/dismiss/types.js +3 -0
  38. package/lib/cjs/components/dismiss/types.js.map +1 -0
  39. package/lib/cjs/components/drawer/drawer.js +347 -0
  40. package/lib/cjs/components/drawer/drawer.js.map +1 -0
  41. package/lib/cjs/components/drawer/index.js +6 -0
  42. package/lib/cjs/components/drawer/index.js.map +1 -0
  43. package/lib/cjs/components/drawer/types.js +3 -0
  44. package/lib/cjs/components/drawer/types.js.map +1 -0
  45. package/lib/cjs/components/dropdown/dropdown.js +403 -0
  46. package/lib/cjs/components/dropdown/dropdown.js.map +1 -0
  47. package/lib/cjs/components/dropdown/index.js +6 -0
  48. package/lib/cjs/components/dropdown/index.js.map +1 -0
  49. package/lib/cjs/components/dropdown/types.js +3 -0
  50. package/lib/cjs/components/dropdown/types.js.map +1 -0
  51. package/lib/cjs/components/image-input/image-input.js +191 -0
  52. package/lib/cjs/components/image-input/image-input.js.map +1 -0
  53. package/lib/cjs/components/image-input/index.js +6 -0
  54. package/lib/cjs/components/image-input/index.js.map +1 -0
  55. package/lib/cjs/components/image-input/types.js +3 -0
  56. package/lib/cjs/components/image-input/types.js.map +1 -0
  57. package/lib/cjs/components/menu/index.js +6 -0
  58. package/lib/cjs/components/menu/index.js.map +1 -0
  59. package/lib/cjs/components/menu/menu.js +1021 -0
  60. package/lib/cjs/components/menu/menu.js.map +1 -0
  61. package/lib/cjs/components/menu/types.js +3 -0
  62. package/lib/cjs/components/menu/types.js.map +1 -0
  63. package/lib/cjs/components/modal/index.js +6 -0
  64. package/lib/cjs/components/modal/index.js.map +1 -0
  65. package/lib/cjs/components/modal/modal.js +316 -0
  66. package/lib/cjs/components/modal/modal.js.map +1 -0
  67. package/lib/cjs/components/modal/types.js +3 -0
  68. package/lib/cjs/components/modal/types.js.map +1 -0
  69. package/lib/cjs/components/reparent/index.js +6 -0
  70. package/lib/cjs/components/reparent/index.js.map +1 -0
  71. package/lib/cjs/components/reparent/reparent.js +93 -0
  72. package/lib/cjs/components/reparent/reparent.js.map +1 -0
  73. package/lib/cjs/components/reparent/types.js +3 -0
  74. package/lib/cjs/components/reparent/types.js.map +1 -0
  75. package/lib/cjs/components/scrollable/index.js +6 -0
  76. package/lib/cjs/components/scrollable/index.js.map +1 -0
  77. package/lib/cjs/components/scrollable/scrollable.js +259 -0
  78. package/lib/cjs/components/scrollable/scrollable.js.map +1 -0
  79. package/lib/cjs/components/scrollable/types.js +3 -0
  80. package/lib/cjs/components/scrollable/types.js.map +1 -0
  81. package/lib/cjs/components/scrollspy/index.js +6 -0
  82. package/lib/cjs/components/scrollspy/index.js.map +1 -0
  83. package/lib/cjs/components/scrollspy/scrollspy.js +174 -0
  84. package/lib/cjs/components/scrollspy/scrollspy.js.map +1 -0
  85. package/lib/cjs/components/scrollspy/types.js +3 -0
  86. package/lib/cjs/components/scrollspy/types.js.map +1 -0
  87. package/lib/cjs/components/scrollto/index.js +6 -0
  88. package/lib/cjs/components/scrollto/index.js.map +1 -0
  89. package/lib/cjs/components/scrollto/scrollto.js +103 -0
  90. package/lib/cjs/components/scrollto/scrollto.js.map +1 -0
  91. package/lib/cjs/components/scrollto/types.js +3 -0
  92. package/lib/cjs/components/scrollto/types.js.map +1 -0
  93. package/lib/cjs/components/stepper/index.js +6 -0
  94. package/lib/cjs/components/stepper/index.js.map +1 -0
  95. package/lib/cjs/components/stepper/stepper.js +258 -0
  96. package/lib/cjs/components/stepper/stepper.js.map +1 -0
  97. package/lib/cjs/components/stepper/types.js +3 -0
  98. package/lib/cjs/components/stepper/types.js.map +1 -0
  99. package/lib/cjs/components/sticky/index.js +6 -0
  100. package/lib/cjs/components/sticky/index.js.map +1 -0
  101. package/lib/cjs/components/sticky/sticky.js +297 -0
  102. package/lib/cjs/components/sticky/sticky.js.map +1 -0
  103. package/lib/cjs/components/sticky/types.js +3 -0
  104. package/lib/cjs/components/sticky/types.js.map +1 -0
  105. package/lib/cjs/components/tabs/index.js +6 -0
  106. package/lib/cjs/components/tabs/index.js.map +1 -0
  107. package/lib/cjs/components/tabs/tabs.js +146 -0
  108. package/lib/cjs/components/tabs/tabs.js.map +1 -0
  109. package/lib/cjs/components/tabs/types.js +3 -0
  110. package/lib/cjs/components/tabs/types.js.map +1 -0
  111. package/lib/cjs/components/theme/index.js +6 -0
  112. package/lib/cjs/components/theme/index.js.map +1 -0
  113. package/lib/cjs/components/theme/theme.js +147 -0
  114. package/lib/cjs/components/theme/theme.js.map +1 -0
  115. package/lib/cjs/components/theme/types.js +3 -0
  116. package/lib/cjs/components/theme/types.js.map +1 -0
  117. package/lib/cjs/components/toggle/index.js +6 -0
  118. package/lib/cjs/components/toggle/index.js.map +1 -0
  119. package/lib/cjs/components/toggle/toggle.js +139 -0
  120. package/lib/cjs/components/toggle/toggle.js.map +1 -0
  121. package/lib/cjs/components/toggle/types.js +3 -0
  122. package/lib/cjs/components/toggle/types.js.map +1 -0
  123. package/lib/cjs/components/toggle-password/index.js +6 -0
  124. package/lib/cjs/components/toggle-password/index.js.map +1 -0
  125. package/lib/cjs/components/toggle-password/toggle-password.js +131 -0
  126. package/lib/cjs/components/toggle-password/toggle-password.js.map +1 -0
  127. package/lib/cjs/components/toggle-password/types.js +3 -0
  128. package/lib/cjs/components/toggle-password/types.js.map +1 -0
  129. package/lib/cjs/components/tooltip/index.js +6 -0
  130. package/lib/cjs/components/tooltip/index.js.map +1 -0
  131. package/lib/cjs/components/tooltip/tooltip.js +271 -0
  132. package/lib/cjs/components/tooltip/tooltip.js.map +1 -0
  133. package/lib/cjs/components/tooltip/types.js +3 -0
  134. package/lib/cjs/components/tooltip/types.js.map +1 -0
  135. package/lib/cjs/helpers/data.js +33 -0
  136. package/lib/cjs/helpers/data.js.map +1 -0
  137. package/lib/cjs/helpers/dom.js +297 -0
  138. package/lib/cjs/helpers/dom.js.map +1 -0
  139. package/lib/cjs/helpers/event-handler.js +36 -0
  140. package/lib/cjs/helpers/event-handler.js.map +1 -0
  141. package/lib/cjs/helpers/utils.js +94 -0
  142. package/lib/cjs/helpers/utils.js.map +1 -0
  143. package/lib/cjs/index.js +105 -0
  144. package/lib/cjs/index.js.map +1 -0
  145. package/lib/cjs/types.js +3 -0
  146. package/lib/cjs/types.js.map +1 -0
  147. package/lib/esm/components/accordion/accordion.js +165 -0
  148. package/lib/esm/components/accordion/accordion.js.map +1 -0
  149. package/lib/esm/components/accordion/index.js +2 -0
  150. package/lib/esm/components/accordion/index.js.map +1 -0
  151. package/lib/esm/components/accordion/types.js +2 -0
  152. package/lib/esm/components/accordion/types.js.map +1 -0
  153. package/lib/esm/components/collapse/collapse.js +166 -0
  154. package/lib/esm/components/collapse/collapse.js.map +1 -0
  155. package/lib/esm/components/collapse/index.js +2 -0
  156. package/lib/esm/components/collapse/index.js.map +1 -0
  157. package/lib/esm/components/collapse/types.js +2 -0
  158. package/lib/esm/components/collapse/types.js.map +1 -0
  159. package/lib/esm/components/component.js +133 -0
  160. package/lib/esm/components/component.js.map +1 -0
  161. package/lib/esm/components/config.js +24 -0
  162. package/lib/esm/components/config.js.map +1 -0
  163. package/lib/esm/components/config.umd.js +23 -0
  164. package/lib/esm/components/config.umd.js.map +1 -0
  165. package/lib/esm/components/constants.js +12 -0
  166. package/lib/esm/components/constants.js.map +1 -0
  167. package/lib/esm/components/datatable/datatable.js +1461 -0
  168. package/lib/esm/components/datatable/datatable.js.map +1 -0
  169. package/lib/esm/components/datatable/index.js +2 -0
  170. package/lib/esm/components/datatable/index.js.map +1 -0
  171. package/lib/esm/components/datatable/types.js +2 -0
  172. package/lib/esm/components/datatable/types.js.map +1 -0
  173. package/lib/esm/components/dismiss/dismiss.js +128 -0
  174. package/lib/esm/components/dismiss/dismiss.js.map +1 -0
  175. package/lib/esm/components/dismiss/index.js +2 -0
  176. package/lib/esm/components/dismiss/index.js.map +1 -0
  177. package/lib/esm/components/dismiss/types.js +2 -0
  178. package/lib/esm/components/dismiss/types.js.map +1 -0
  179. package/lib/esm/components/drawer/drawer.js +344 -0
  180. package/lib/esm/components/drawer/drawer.js.map +1 -0
  181. package/lib/esm/components/drawer/index.js +2 -0
  182. package/lib/esm/components/drawer/index.js.map +1 -0
  183. package/lib/esm/components/drawer/types.js +2 -0
  184. package/lib/esm/components/drawer/types.js.map +1 -0
  185. package/lib/esm/components/dropdown/dropdown.js +400 -0
  186. package/lib/esm/components/dropdown/dropdown.js.map +1 -0
  187. package/lib/esm/components/dropdown/index.js +2 -0
  188. package/lib/esm/components/dropdown/index.js.map +1 -0
  189. package/lib/esm/components/dropdown/types.js +2 -0
  190. package/lib/esm/components/dropdown/types.js.map +1 -0
  191. package/lib/esm/components/image-input/image-input.js +188 -0
  192. package/lib/esm/components/image-input/image-input.js.map +1 -0
  193. package/lib/esm/components/image-input/index.js +2 -0
  194. package/lib/esm/components/image-input/index.js.map +1 -0
  195. package/lib/esm/components/image-input/types.js +2 -0
  196. package/lib/esm/components/image-input/types.js.map +1 -0
  197. package/lib/esm/components/menu/index.js +2 -0
  198. package/lib/esm/components/menu/index.js.map +1 -0
  199. package/lib/esm/components/menu/menu.js +1018 -0
  200. package/lib/esm/components/menu/menu.js.map +1 -0
  201. package/lib/esm/components/menu/types.js +2 -0
  202. package/lib/esm/components/menu/types.js.map +1 -0
  203. package/lib/esm/components/modal/index.js +2 -0
  204. package/lib/esm/components/modal/index.js.map +1 -0
  205. package/lib/esm/components/modal/modal.js +313 -0
  206. package/lib/esm/components/modal/modal.js.map +1 -0
  207. package/lib/esm/components/modal/types.js +2 -0
  208. package/lib/esm/components/modal/types.js.map +1 -0
  209. package/lib/esm/components/reparent/index.js +2 -0
  210. package/lib/esm/components/reparent/index.js.map +1 -0
  211. package/lib/esm/components/reparent/reparent.js +90 -0
  212. package/lib/esm/components/reparent/reparent.js.map +1 -0
  213. package/lib/esm/components/reparent/types.js +2 -0
  214. package/lib/esm/components/reparent/types.js.map +1 -0
  215. package/lib/esm/components/scrollable/index.js +2 -0
  216. package/lib/esm/components/scrollable/index.js.map +1 -0
  217. package/lib/esm/components/scrollable/scrollable.js +256 -0
  218. package/lib/esm/components/scrollable/scrollable.js.map +1 -0
  219. package/lib/esm/components/scrollable/types.js +2 -0
  220. package/lib/esm/components/scrollable/types.js.map +1 -0
  221. package/lib/esm/components/scrollspy/index.js +2 -0
  222. package/lib/esm/components/scrollspy/index.js.map +1 -0
  223. package/lib/esm/components/scrollspy/scrollspy.js +171 -0
  224. package/lib/esm/components/scrollspy/scrollspy.js.map +1 -0
  225. package/lib/esm/components/scrollspy/types.js +2 -0
  226. package/lib/esm/components/scrollspy/types.js.map +1 -0
  227. package/lib/esm/components/scrollto/index.js +2 -0
  228. package/lib/esm/components/scrollto/index.js.map +1 -0
  229. package/lib/esm/components/scrollto/scrollto.js +100 -0
  230. package/lib/esm/components/scrollto/scrollto.js.map +1 -0
  231. package/lib/esm/components/scrollto/types.js +2 -0
  232. package/lib/esm/components/scrollto/types.js.map +1 -0
  233. package/lib/esm/components/stepper/index.js +2 -0
  234. package/lib/esm/components/stepper/index.js.map +1 -0
  235. package/lib/esm/components/stepper/stepper.js +255 -0
  236. package/lib/esm/components/stepper/stepper.js.map +1 -0
  237. package/lib/esm/components/stepper/types.js +2 -0
  238. package/lib/esm/components/stepper/types.js.map +1 -0
  239. package/lib/esm/components/sticky/index.js +2 -0
  240. package/lib/esm/components/sticky/index.js.map +1 -0
  241. package/lib/esm/components/sticky/sticky.js +294 -0
  242. package/lib/esm/components/sticky/sticky.js.map +1 -0
  243. package/lib/esm/components/sticky/types.js +2 -0
  244. package/lib/esm/components/sticky/types.js.map +1 -0
  245. package/lib/esm/components/tabs/index.js +2 -0
  246. package/lib/esm/components/tabs/index.js.map +1 -0
  247. package/lib/esm/components/tabs/tabs.js +143 -0
  248. package/lib/esm/components/tabs/tabs.js.map +1 -0
  249. package/lib/esm/components/tabs/types.js +2 -0
  250. package/lib/esm/components/tabs/types.js.map +1 -0
  251. package/lib/esm/components/theme/index.js +2 -0
  252. package/lib/esm/components/theme/index.js.map +1 -0
  253. package/lib/esm/components/theme/theme.js +144 -0
  254. package/lib/esm/components/theme/theme.js.map +1 -0
  255. package/lib/esm/components/theme/types.js +2 -0
  256. package/lib/esm/components/theme/types.js.map +1 -0
  257. package/lib/esm/components/toggle/index.js +2 -0
  258. package/lib/esm/components/toggle/index.js.map +1 -0
  259. package/lib/esm/components/toggle/toggle.js +136 -0
  260. package/lib/esm/components/toggle/toggle.js.map +1 -0
  261. package/lib/esm/components/toggle/types.js +2 -0
  262. package/lib/esm/components/toggle/types.js.map +1 -0
  263. package/lib/esm/components/toggle-password/index.js +2 -0
  264. package/lib/esm/components/toggle-password/index.js.map +1 -0
  265. package/lib/esm/components/toggle-password/toggle-password.js +128 -0
  266. package/lib/esm/components/toggle-password/toggle-password.js.map +1 -0
  267. package/lib/esm/components/toggle-password/types.js +2 -0
  268. package/lib/esm/components/toggle-password/types.js.map +1 -0
  269. package/lib/esm/components/tooltip/index.js +2 -0
  270. package/lib/esm/components/tooltip/index.js.map +1 -0
  271. package/lib/esm/components/tooltip/tooltip.js +268 -0
  272. package/lib/esm/components/tooltip/tooltip.js.map +1 -0
  273. package/lib/esm/components/tooltip/types.js +2 -0
  274. package/lib/esm/components/tooltip/types.js.map +1 -0
  275. package/lib/esm/helpers/data.js +31 -0
  276. package/lib/esm/helpers/data.js.map +1 -0
  277. package/lib/esm/helpers/dom.js +295 -0
  278. package/lib/esm/helpers/dom.js.map +1 -0
  279. package/lib/esm/helpers/event-handler.js +34 -0
  280. package/lib/esm/helpers/event-handler.js.map +1 -0
  281. package/lib/esm/helpers/utils.js +92 -0
  282. package/lib/esm/helpers/utils.js.map +1 -0
  283. package/lib/esm/index.js +79 -0
  284. package/lib/esm/index.js.map +1 -0
  285. package/lib/esm/types.js +2 -0
  286. package/lib/esm/types.js.map +1 -0
  287. package/package.json +85 -0
  288. package/prettier.config.js +9 -0
  289. package/src/components/accordion/accordion-menu.css +51 -0
  290. package/src/components/accordion/accordion.css +86 -0
  291. package/src/components/accordion/accordion.ts +221 -0
  292. package/src/components/accordion/index.ts +7 -0
  293. package/src/components/accordion/types.ts +16 -0
  294. package/src/components/alert/alert.css +282 -0
  295. package/src/components/avatar/avatar.css +46 -0
  296. package/src/components/badge/badge.css +176 -0
  297. package/src/components/breadcrumb/breadcrumb.css +38 -0
  298. package/src/components/btn/btn.css +227 -0
  299. package/src/components/card/card.css +158 -0
  300. package/src/components/checkbox/checkbox.css +74 -0
  301. package/src/components/collapse/collapse.css +14 -0
  302. package/src/components/collapse/collapse.ts +200 -0
  303. package/src/components/collapse/index.ts +7 -0
  304. package/src/components/collapse/types.ts +16 -0
  305. package/src/components/component.ts +132 -0
  306. package/src/components/constants.ts +16 -0
  307. package/src/components/datatable/datatable-checkbox.ts +236 -0
  308. package/src/components/datatable/datatable-sort.ts +154 -0
  309. package/src/components/datatable/datatable.css +110 -0
  310. package/src/components/datatable/datatable.ts +1657 -0
  311. package/src/components/datatable/index.ts +19 -0
  312. package/src/components/datatable/types.ts +203 -0
  313. package/src/components/datepicker/calendar.ts +1397 -0
  314. package/src/components/datepicker/config.ts +368 -0
  315. package/src/components/datepicker/datepicker.css +7 -0
  316. package/src/components/datepicker/datepicker.ts +1287 -0
  317. package/src/components/datepicker/dropdown.ts +757 -0
  318. package/src/components/datepicker/events.ts +149 -0
  319. package/src/components/datepicker/index.ts +10 -0
  320. package/src/components/datepicker/keyboard.ts +646 -0
  321. package/src/components/datepicker/locales.ts +80 -0
  322. package/src/components/datepicker/templates.ts +792 -0
  323. package/src/components/datepicker/types.ts +154 -0
  324. package/src/components/datepicker/utils.ts +631 -0
  325. package/src/components/dismiss/dismiss.css +10 -0
  326. package/src/components/dismiss/dismiss.ts +152 -0
  327. package/src/components/dismiss/index.ts +7 -0
  328. package/src/components/dismiss/types.ts +17 -0
  329. package/src/components/drawer/drawer.css +97 -0
  330. package/src/components/drawer/drawer.ts +437 -0
  331. package/src/components/drawer/index.ts +7 -0
  332. package/src/components/drawer/types.ts +25 -0
  333. package/src/components/dropdown/dropdown-menu.css +56 -0
  334. package/src/components/dropdown/dropdown.css +46 -0
  335. package/src/components/dropdown/dropdown.ts +549 -0
  336. package/src/components/dropdown/index.ts +7 -0
  337. package/src/components/dropdown/types.ts +28 -0
  338. package/src/components/form/form.css +54 -0
  339. package/src/components/image-input/image-input.css +56 -0
  340. package/src/components/image-input/image-input.ts +249 -0
  341. package/src/components/image-input/index.ts +10 -0
  342. package/src/components/image-input/types.ts +12 -0
  343. package/src/components/input/input-group.css +42 -0
  344. package/src/components/input/input.css +136 -0
  345. package/src/components/kbd/kbd.css +30 -0
  346. package/src/components/label/label.css +20 -0
  347. package/src/components/link/link.css +81 -0
  348. package/src/components/modal/index.ts +7 -0
  349. package/src/components/modal/modal.css +73 -0
  350. package/src/components/modal/modal.ts +382 -0
  351. package/src/components/modal/types.ts +21 -0
  352. package/src/components/pagination/pagination.css +26 -0
  353. package/src/components/popover/popover.css +22 -0
  354. package/src/components/progress/progress.css +51 -0
  355. package/src/components/radio/radio.css +51 -0
  356. package/src/components/reparent/index.ts +7 -0
  357. package/src/components/reparent/reparent.ts +109 -0
  358. package/src/components/reparent/types.ts +15 -0
  359. package/src/components/scrollable/index.ts +10 -0
  360. package/src/components/scrollable/scrollable.css +29 -0
  361. package/src/components/scrollable/scrollable.ts +297 -0
  362. package/src/components/scrollable/types.ts +16 -0
  363. package/src/components/scrollspy/index.ts +7 -0
  364. package/src/components/scrollspy/scrollspy.css +13 -0
  365. package/src/components/scrollspy/scrollspy.ts +224 -0
  366. package/src/components/scrollspy/types.ts +15 -0
  367. package/src/components/scrollto/index.ts +7 -0
  368. package/src/components/scrollto/scrollto.ts +127 -0
  369. package/src/components/scrollto/types.ts +15 -0
  370. package/src/components/select/combobox.ts +305 -0
  371. package/src/components/select/config.ts +324 -0
  372. package/src/components/select/dropdown.ts +510 -0
  373. package/src/components/select/index.ts +13 -0
  374. package/src/components/select/option.ts +43 -0
  375. package/src/components/select/remote.ts +477 -0
  376. package/src/components/select/search.ts +430 -0
  377. package/src/components/select/select.css +105 -0
  378. package/src/components/select/select.ts +1916 -0
  379. package/src/components/select/tags.ts +123 -0
  380. package/src/components/select/templates.ts +531 -0
  381. package/src/components/select/types.ts +36 -0
  382. package/src/components/select/utils.ts +747 -0
  383. package/src/components/select/variants.css +5 -0
  384. package/src/components/separator/separator.css +14 -0
  385. package/src/components/skeleton/skeleton.css +10 -0
  386. package/src/components/stepper/index.ts +7 -0
  387. package/src/components/stepper/stepper.css +49 -0
  388. package/src/components/stepper/stepper.ts +308 -0
  389. package/src/components/stepper/types.ts +13 -0
  390. package/src/components/sticky/index.ts +7 -0
  391. package/src/components/sticky/sticky.css +22 -0
  392. package/src/components/sticky/sticky.ts +381 -0
  393. package/src/components/sticky/types.ts +23 -0
  394. package/src/components/switch/switch.css +110 -0
  395. package/src/components/table/table.css +168 -0
  396. package/src/components/tabs/index.ts +7 -0
  397. package/src/components/tabs/tabs.css +40 -0
  398. package/src/components/tabs/tabs.ts +190 -0
  399. package/src/components/tabs/types.ts +13 -0
  400. package/src/components/textarea/textarea.css +35 -0
  401. package/src/components/theme-switch/index.ts +10 -0
  402. package/src/components/theme-switch/theme-switch.css +22 -0
  403. package/src/components/theme-switch/theme-switch.ts +176 -0
  404. package/src/components/theme-switch/types.ts +15 -0
  405. package/src/components/toggle/index.ts +7 -0
  406. package/src/components/toggle/toggle.css +13 -0
  407. package/src/components/toggle/toggle.ts +173 -0
  408. package/src/components/toggle/types.ts +18 -0
  409. package/src/components/toggle-group/toggle-group.css +55 -0
  410. package/src/components/toggle-password/index.ts +10 -0
  411. package/src/components/toggle-password/toggle-password.css +13 -0
  412. package/src/components/toggle-password/toggle-password.ts +159 -0
  413. package/src/components/toggle-password/types.ts +13 -0
  414. package/src/components/tooltip/index.ts +7 -0
  415. package/src/components/tooltip/tooltip.css +18 -0
  416. package/src/components/tooltip/tooltip.ts +361 -0
  417. package/src/components/tooltip/types.ts +28 -0
  418. package/src/helpers/data.ts +46 -0
  419. package/src/helpers/dom.ts +405 -0
  420. package/src/helpers/event-handler.ts +61 -0
  421. package/src/helpers/utils.ts +183 -0
  422. package/src/index.ts +113 -0
  423. package/src/types.ts +23 -0
  424. package/styles.css +48 -0
  425. package/tsconfig.json +17 -0
  426. package/webpack.config.js +113 -0
@@ -0,0 +1,123 @@
1
+ /**
2
+ * KTUI - Free & Open-Source Tailwind UI Components by Keenthemes
3
+ * Copyright 2025 by Keenthemes Inc
4
+ * @version: 1.0.0
5
+ */
6
+ import { KTSelectConfigInterface } from './config';
7
+ import { KTSelect } from './select';
8
+ import { defaultTemplates } from './templates';
9
+ import { EventManager } from './utils';
10
+
11
+ /**
12
+ * KTSelectTags - Handles tags-specific functionality for KTSelect
13
+ */
14
+ export class KTSelectTags {
15
+ private _select: KTSelect;
16
+ private _config: KTSelectConfigInterface;
17
+ private _valueDisplayElement: HTMLElement;
18
+ private _eventManager: EventManager;
19
+
20
+ /**
21
+ * Constructor: Initializes the tags component
22
+ */
23
+ constructor(select: KTSelect) {
24
+ this._select = select;
25
+ this._config = select.getConfig();
26
+ this._valueDisplayElement = select.getValueDisplayElement();
27
+ this._eventManager = new EventManager();
28
+
29
+ if (this._config.debug) console.log('KTSelectTags initialized');
30
+ }
31
+
32
+ /**
33
+ * Update selected tags display
34
+ * Renders selected options as tags in the display element
35
+ */
36
+ public updateTagsDisplay(selectedOptions: string[]): void {
37
+ // Clear existing content
38
+ this._valueDisplayElement.innerHTML = '';
39
+
40
+ // If no options selected, show placeholder
41
+ if (selectedOptions.length === 0) {
42
+ this._valueDisplayElement.textContent = this._config.placeholder || '';
43
+ return;
44
+ }
45
+
46
+ // Create and append a tag element for each selected option
47
+ selectedOptions.forEach((optionValue) => {
48
+ const tagElement = this._createTagElement(optionValue);
49
+ this._valueDisplayElement.appendChild(tagElement);
50
+ });
51
+ }
52
+
53
+ /**
54
+ * Create tag element for a selected option
55
+ */
56
+ private _createTagElement(optionValue: string): HTMLElement {
57
+ const optionLabel = this._getOptionLabel(optionValue);
58
+ // Create a mock option object to pass to the tag template
59
+ const mockOption = {
60
+ id: optionValue,
61
+ title: optionLabel,
62
+ selected: true,
63
+ };
64
+
65
+ // Use the tag template
66
+ const tag = defaultTemplates.tag(mockOption, this._config);
67
+
68
+ // Add event listener to the close button
69
+ const closeButton = tag.querySelector(
70
+ `[data-kt-select-remove-button]`,
71
+ ) as HTMLElement;
72
+
73
+ if (closeButton) {
74
+ this._eventManager.addListener(closeButton, 'click', (event: Event) => {
75
+ event.stopPropagation();
76
+ this._removeTag(optionValue);
77
+ });
78
+ }
79
+
80
+ return tag;
81
+ }
82
+
83
+ /**
84
+ * Get the label/text for an option by its value
85
+ */
86
+ private _getOptionLabel(optionValue: string): string {
87
+ // First look for an option element in the dropdown with matching value
88
+ const optionElements = this._select.getOptionsElement();
89
+ for (const option of Array.from(optionElements)) {
90
+ if ((option as HTMLElement).dataset.value === optionValue) {
91
+ return (option as HTMLElement).textContent?.trim() || optionValue;
92
+ }
93
+ }
94
+
95
+ // If not found in dropdown, look in original select element
96
+ const originalOptions = this._select
97
+ .getElement()
98
+ .querySelectorAll('option');
99
+ for (const option of Array.from(originalOptions)) {
100
+ if ((option as HTMLOptionElement).value === optionValue) {
101
+ return (option as HTMLOptionElement).textContent?.trim() || optionValue;
102
+ }
103
+ }
104
+
105
+ // If still not found, return the value itself
106
+ return optionValue;
107
+ }
108
+
109
+ /**
110
+ * Remove a tag and its selection
111
+ */
112
+ private _removeTag(optionValue: string): void {
113
+ // Delegate to the select component to handle state changes
114
+ this._select.toggleSelection(optionValue);
115
+ }
116
+
117
+ /**
118
+ * Clean up resources used by this module
119
+ */
120
+ public destroy(): void {
121
+ this._eventManager.removeAllListeners(null);
122
+ }
123
+ }
@@ -0,0 +1,531 @@
1
+ /**
2
+ * KTUI - Free & Open-Source Tailwind UI Components by Keenthemes
3
+ * Copyright 2025 by Keenthemes Inc
4
+ * @version: 1.0.0
5
+ */
6
+ import { KTSelectConfigInterface, KTSelectOption } from './config';
7
+ import { SelectMode } from './types';
8
+
9
+ /**
10
+ * Default HTML string templates for KTSelect. All UI structure is defined here.
11
+ * Users can override any template by providing a matching key in the config.templates object.
12
+ */
13
+ const defaultTemplateStrings = {
14
+ dropdownContent: `<div data-kt-select-dropdown-content class="kt-select-dropdown hidden" style="z-index: {{zindex}};">{{content}}</div>`,
15
+ optionsContainer: `<ul role="listbox" aria-label="{{label}}" data-kt-select-options-container style="max-height: {{height}}px; overflow-y: auto;">{{options}}</ul>`,
16
+ emptyOption: `<option value="">{{placeholder}}</option>`,
17
+ errorOption: `<option value="" disabled selected>{{errorMessage}}</option>`, // Template for error <option>
18
+
19
+ loadMore: `<li class="py-2 px-4 text-center text-gray-600 cursor-pointer hover:bg-gray-100" data-kt-select-load-more>{{loadMoreText}}</li>`,
20
+ dropdown: `<div data-kt-select-dropdown-content class="absolute z-10 w-full mt-2 bg-white border border-gray-200 rounded-md shadow-md">
21
+ {{search}}
22
+ <ul role="listbox" aria-label="{{label}}" data-kt-select-options-container style="max-height: {{height}}px; overflow-y: auto;">
23
+ {{options}}
24
+ </ul>
25
+ </div>`,
26
+ error: `<li class="px-3 py-2 text-red-500" role="alert">{{errorMessage}}</li>`,
27
+
28
+ highlight: `<span class="highlight">{{text}}</span>`,
29
+ main: `<div data-kt-select-wrapper class="relative" data-kt-select-mode="{{mode}}"></div>`,
30
+ displayCombobox: `<div class="relative flex items-center w-full">
31
+ <input data-kt-select-search data-kt-select-display data-kt-select-value type="text" class="flex-1 w-full items-center justify-between px-3 py-2 border border-gray-300 rounded-md cursor-pointer focus:outline-none focus:ring-2 focus:ring-blue-200 focus:border-blue-400" placeholder="{{placeholder}}" role="searchbox" aria-label="{{label}}" {{disabled}} />
32
+ <button type="button" data-kt-select-clear-button class="absolute right-3 hidden text-gray-400 hover:text-gray-600" aria-label="Clear selection">
33
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
34
+ <line x1="18" y1="6" x2="6" y2="18"></line>
35
+ <line x1="6" y1="6" x2="18" y2="18"></line>
36
+ </svg>
37
+ </button>
38
+ </div>`,
39
+
40
+ icon: `<span class="option-icon mr-2"><img src="{{icon}}" class="rounded-full w-6 h-6" /></span>`,
41
+ description: `<div class="option-description text-sm text-gray-500">{{description}}</div>`,
42
+
43
+ display: `<div data-kt-select-display class="flex items-center justify-between px-3 py-2 border border-gray-300 rounded-md cursor-pointer focus:outline-none focus:ring-2 focus:ring-blue-200 focus:border-blue-400" tabindex="{{tabindex}}" role="button" aria-haspopup="listbox" aria-expanded="false" aria-label="{{label}}" {{disabled}}>
44
+ <span data-kt-select-value>{{placeholder}}</span>
45
+ <span data-kt-select-arrow class="ml-2">
46
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
47
+ <polyline points="6 9 12 15 18 9"></polyline>
48
+ </svg>
49
+ </span>
50
+ </div>`,
51
+ option: `<li data-kt-select-option data-value="{{value}}" class="px-3 py-2 cursor-pointer hover:bg-gray-100 flex items-center{{selectedClass}}{{disabledClass}}" role="option" {{selected}} {{disabled}}>{{icon}}<div class="option-content"><div class="option-title" data-kt-option-title>{{text}}</div>{{description}}</div></li>`,
52
+
53
+ optionGroup: `<li role="group" aria-label="{{label}}" class="py-1"><div class="px-3 py-1 text-xs font-semibold text-gray-500 uppercase">{{label}}</div><ul>{{optionsHtml}}</ul></li>`,
54
+ search: `<div class="px-3 py-2 border-b border-gray-200"><input type="text" data-kt-select-search placeholder="{{searchPlaceholder}}" class="w-full border-none focus:outline-none text-sm" role="searchbox" aria-label="{{searchPlaceholder}}"/></div>`,
55
+ noResults: `<li class="px-3 py-2 text-gray-500" role="status">{{searchNotFoundText}}</li>`,
56
+ loading: `<li class="px-3 py-2 text-gray-500 italic" role="status" aria-live="polite">{{loadingMessage}}</li>`,
57
+ tag: `<div data-kt-select-tag class="inline-flex items-center bg-blue-50 border border-blue-100 rounded px-2 py-1 text-sm mr-1 mb-1"><span>{{title}}</span><span data-kt-select-remove-button data-value="{{id}}" class="ml-1 text-blue-400 hover:text-blue-600 cursor-pointer" role="button" aria-label="Remove {{safeTitle}}" tabindex="0"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg></span></div>`,
58
+ };
59
+
60
+ /**
61
+ * Template interface for KTSelect component
62
+ * Each method returns an HTML string or HTMLElement
63
+ */
64
+ export interface KTSelectTemplateInterface {
65
+ /**
66
+ * Renders the dropdown content container
67
+ */
68
+ dropdownContent: (
69
+ config: KTSelectConfigInterface & { zindex?: number; content?: string },
70
+ ) => HTMLElement;
71
+ /**
72
+ * Renders the options container
73
+ */
74
+ optionsContainer: (
75
+ config: KTSelectConfigInterface & { options?: string },
76
+ ) => HTMLElement;
77
+ /**
78
+ * Renders an empty <option> for native select
79
+ */
80
+ emptyOption: (
81
+ config: KTSelectConfigInterface & { placeholder?: string },
82
+ ) => HTMLOptionElement;
83
+ /**
84
+ * Renders an error <option> for the native select
85
+ */
86
+ errorOption: (
87
+ config: KTSelectConfigInterface & { errorMessage: string },
88
+ ) => HTMLElement;
89
+ /**
90
+ * Renders the load more button for pagination
91
+ */
92
+ loadMore: (config: KTSelectConfigInterface) => HTMLElement;
93
+ /**
94
+ * Renders an error message in the dropdown
95
+ */
96
+ error: (config: KTSelectConfigInterface & { errorMessage: string }) => string;
97
+
98
+ highlight: (config: KTSelectConfigInterface, text: string) => HTMLElement;
99
+
100
+ // Main components
101
+ main: (config: KTSelectConfigInterface) => HTMLElement;
102
+ display: (config: KTSelectConfigInterface) => HTMLElement;
103
+ dropdown: (
104
+ config: KTSelectConfigInterface,
105
+ optionsHtml: string,
106
+ ) => HTMLElement;
107
+
108
+ // Icon rendering
109
+ icon: (icon: string, config: KTSelectConfigInterface) => HTMLElement;
110
+ description: (
111
+ description: string,
112
+ config: KTSelectConfigInterface,
113
+ ) => HTMLElement;
114
+
115
+ // Option rendering
116
+ option: (
117
+ option: KTSelectOption | HTMLOptionElement,
118
+ config: KTSelectConfigInterface,
119
+ ) => HTMLElement;
120
+ optionGroup: (
121
+ label: string,
122
+ optionsHtml: string,
123
+ config: KTSelectConfigInterface,
124
+ ) => HTMLElement;
125
+
126
+ // Search and empty states
127
+ search: (config: KTSelectConfigInterface) => HTMLElement;
128
+ noResults: (config: KTSelectConfigInterface) => HTMLElement;
129
+ loading: (
130
+ config: KTSelectConfigInterface,
131
+ loadingMessage: string,
132
+ ) => HTMLElement;
133
+
134
+ // Multi-select
135
+ tag: (option: KTSelectOption, config: KTSelectConfigInterface) => HTMLElement;
136
+ selectedDisplay: (
137
+ selectedOptions: KTSelectOption[],
138
+ config: KTSelectConfigInterface,
139
+ ) => string;
140
+ }
141
+
142
+ /**
143
+ * Default templates for KTSelect component
144
+ */
145
+ function stringToElement(html: string): HTMLElement {
146
+ const template = document.createElement('template');
147
+ template.innerHTML = html.trim();
148
+ return template.content.firstElementChild as HTMLElement;
149
+ }
150
+
151
+ /**
152
+ * User-supplied template overrides. Use setTemplateStrings() to add or update.
153
+ */
154
+ let userTemplateStrings: Partial<typeof defaultTemplateStrings> = {};
155
+
156
+ /**
157
+ * Register or update user template overrides.
158
+ * @param templates Partial template object to merge with defaults.
159
+ */
160
+ export function setTemplateStrings(
161
+ templates: Partial<typeof defaultTemplateStrings>,
162
+ ): void {
163
+ userTemplateStrings = { ...userTemplateStrings, ...templates };
164
+ }
165
+
166
+ /**
167
+ * Get the complete template set, merging defaults, user overrides, and config templates.
168
+ * @param config Optional config object with a "templates" property.
169
+ */
170
+ export function getTemplateStrings(
171
+ config?: KTSelectConfigInterface,
172
+ ): typeof defaultTemplateStrings {
173
+ const templates =
174
+ config && typeof config === 'object' && 'templates' in config
175
+ ? (config as any).templates
176
+ : undefined;
177
+ if (templates) {
178
+ return { ...defaultTemplateStrings, ...userTemplateStrings, ...templates };
179
+ }
180
+ return { ...defaultTemplateStrings, ...userTemplateStrings };
181
+ }
182
+
183
+ /**
184
+ * Default templates for KTSelect component
185
+ */
186
+ export const defaultTemplates: KTSelectTemplateInterface = {
187
+ /**
188
+ * Renders a highlighted text
189
+ */
190
+ highlight: (config: KTSelectConfigInterface, text: string) => {
191
+ const template = getTemplateStrings(config).highlight;
192
+ const html = template.replace('{{text}}', text);
193
+ return stringToElement(html);
194
+ },
195
+
196
+ /**
197
+ * Renders the dropdown content
198
+ */
199
+ dropdownContent: (
200
+ config: KTSelectConfigInterface & { zindex?: number; content?: string },
201
+ ) => {
202
+ const template = getTemplateStrings(config).dropdownContent;
203
+ const html = template
204
+ .replace('{{zindex}}', config.zindex ? String(config.zindex) : '')
205
+ .replace('{{content}}', config.content || '');
206
+ return stringToElement(html);
207
+ },
208
+
209
+ /**
210
+ * Renders the options container for the dropdown
211
+ */
212
+ optionsContainer: (
213
+ config: KTSelectConfigInterface & { options?: string },
214
+ ) => {
215
+ const template = getTemplateStrings(config).optionsContainer;
216
+ const html = template
217
+ .replace('{{label}}', config.label || 'Options')
218
+ .replace('{{height}}', config.height ? String(config.height) : '250')
219
+ .replace('{{options}}', config.options || '');
220
+ return stringToElement(html);
221
+ },
222
+
223
+ /**
224
+ * Renders an empty option in the dropdown
225
+ */
226
+ emptyOption: (config: KTSelectConfigInterface & { placeholder?: string }) => {
227
+ const template = getTemplateStrings(config).emptyOption;
228
+ const html = template.replace(
229
+ '{{placeholder}}',
230
+ config.placeholder || 'Select...',
231
+ );
232
+ return stringToElement(html) as HTMLOptionElement;
233
+ },
234
+
235
+ /**
236
+ * Renders an error option in the dropdown
237
+ */
238
+ errorOption: (config: KTSelectConfigInterface & { errorMessage: string }) => {
239
+ const template = getTemplateStrings(config).errorOption;
240
+ const html = template.replace(
241
+ '{{errorMessage}}',
242
+ config.errorMessage || 'An error occurred',
243
+ );
244
+ return stringToElement(html);
245
+ },
246
+
247
+ /**
248
+ * Renders the load more button for pagination
249
+ */
250
+ loadMore: (config: KTSelectConfigInterface): HTMLElement => {
251
+ let html = getTemplateStrings(config).loadMore.replace(
252
+ '{{loadMoreText}}',
253
+ config.loadMoreText || 'Load more...',
254
+ );
255
+ return stringToElement(html);
256
+ },
257
+ /**
258
+ * Renders an error message in the dropdown
259
+ */
260
+ error: (
261
+ config: KTSelectConfigInterface & { errorMessage: string },
262
+ ): string => {
263
+ const template = getTemplateStrings(config).error;
264
+ return template.replace(
265
+ '{{errorMessage}}',
266
+ config.errorMessage || 'An error occurred',
267
+ );
268
+ },
269
+ /**
270
+ * Renders the main container for the select component
271
+ */
272
+ main: (config: KTSelectConfigInterface): HTMLElement => {
273
+ const html = getTemplateStrings(config).main.replace(
274
+ '{{mode}}',
275
+ config.mode || '',
276
+ );
277
+ return stringToElement(html);
278
+ },
279
+
280
+ /**
281
+ * Renders the display element (trigger) for the select
282
+ */
283
+ display: (config: KTSelectConfigInterface): HTMLElement => {
284
+ const isCombobox = config.mode === SelectMode.COMBOBOX;
285
+ if (isCombobox) {
286
+ let html = getTemplateStrings(config)
287
+ .displayCombobox.replace(
288
+ /{{placeholder}}/g,
289
+ config.placeholder || 'Select...',
290
+ )
291
+ .replace(
292
+ /{{label}}/g,
293
+ config.label || config.placeholder || 'Select...',
294
+ )
295
+ .replace('{{disabled}}', config.disabled ? 'disabled' : '');
296
+ return stringToElement(html);
297
+ }
298
+ let html = getTemplateStrings(config)
299
+ .display.replace('{{tabindex}}', config.disabled ? '-1' : '0')
300
+ .replace('{{label}}', config.label || config.placeholder || 'Select...')
301
+ .replace('{{disabled}}', config.disabled ? 'aria-disabled="true"' : '')
302
+ .replace('{{placeholder}}', config.placeholder || 'Select...');
303
+ return stringToElement(html);
304
+ },
305
+
306
+ /**
307
+ * Renders the dropdown content container
308
+ */
309
+ dropdown: (
310
+ config: KTSelectConfigInterface,
311
+ optionsHtml: string,
312
+ ): HTMLElement => {
313
+ const isCombobox = config.mode === SelectMode.COMBOBOX;
314
+ const hasSearch = config.enableSearch && !isCombobox;
315
+ const template = getTemplateStrings(config).dropdown;
316
+ let searchHtml = '';
317
+ if (hasSearch) {
318
+ const searchElement = defaultTemplates.search(config);
319
+ searchHtml = searchElement.outerHTML;
320
+ }
321
+ const html = template
322
+ .replace('{{search}}', searchHtml)
323
+ .replace('{{options}}', optionsHtml)
324
+ .replace('{{label}}', config.label || 'Options')
325
+ .replace('{{height}}', config.height ? String(config.height) : '250');
326
+ return stringToElement(html);
327
+ },
328
+
329
+ /**
330
+ * Renders a single option
331
+ */
332
+ option: (
333
+ option: KTSelectOption | HTMLOptionElement,
334
+ config: KTSelectConfigInterface & { templates: KTSelectTemplateInterface },
335
+ ): HTMLElement => {
336
+ const isHtmlOption = option instanceof HTMLOptionElement;
337
+
338
+ const value = isHtmlOption ? option.value : (option as KTSelectOption).id;
339
+ const text = isHtmlOption ? option.text : (option as KTSelectOption).title;
340
+ const disabled = isHtmlOption
341
+ ? option.disabled
342
+ : (option as any).disabled === true;
343
+ const selected = isHtmlOption
344
+ ? option.selected
345
+ : !!(option as KTSelectOption).selected;
346
+
347
+ // Prefer data-kt-select-option (JSON) if present
348
+ let description: string | undefined;
349
+ let icon: string | undefined;
350
+ if (isHtmlOption) {
351
+ const json = option.getAttribute('data-kt-select-option');
352
+ if (json) {
353
+ try {
354
+ const optionData = JSON.parse(json);
355
+ description = optionData?.description;
356
+ icon = optionData?.icon;
357
+ } catch (e) {
358
+ // fallback to legacy attributes if JSON is invalid
359
+ description =
360
+ option.getAttribute('data-kt-select-option-description') ||
361
+ undefined;
362
+ icon = option.getAttribute('data-kt-select-option-icon') || undefined;
363
+ }
364
+ } else {
365
+ description =
366
+ option.getAttribute('data-kt-select-option-description') || undefined;
367
+ icon = option.getAttribute('data-kt-select-option-icon') || undefined;
368
+ }
369
+ } else {
370
+ description = (option as KTSelectOption).description;
371
+ icon = (option as KTSelectOption).icon;
372
+ }
373
+
374
+ // Build option element with proper accessibility attributes
375
+ const selectedClass = selected ? ' selected' : '';
376
+ const disabledClass = disabled ? ' disabled' : '';
377
+ let html = getTemplateStrings(config)
378
+ .option.replace('{{value}}', value)
379
+ .replace('{{selectedClass}}', selectedClass)
380
+ .replace('{{disabledClass}}', disabledClass)
381
+ .replace(
382
+ '{{selected}}',
383
+ selected ? 'aria-selected="true"' : 'aria-selected="false"',
384
+ )
385
+ .replace('{{disabled}}', disabled ? 'aria-disabled="true"' : '')
386
+ .replace(
387
+ /{{icon}}/g,
388
+ icon ? defaultTemplates.icon(icon, config).outerHTML : '',
389
+ )
390
+ .replace('{{text}}', text)
391
+ .replace(
392
+ /{{description}}/g,
393
+ description
394
+ ? defaultTemplates.description(description, config).outerHTML
395
+ : '',
396
+ );
397
+ return stringToElement(html);
398
+ },
399
+
400
+ /**
401
+ * Renders an icon
402
+ */
403
+ icon: (icon: string, config: KTSelectConfigInterface): HTMLElement => {
404
+ const html = getTemplateStrings(config).icon.replace('{{icon}}', icon);
405
+ return stringToElement(html);
406
+ },
407
+
408
+ /**
409
+ * Renders a description
410
+ */
411
+ description: (
412
+ description: string,
413
+ config: KTSelectConfigInterface,
414
+ ): HTMLElement => {
415
+ const html = getTemplateStrings(config).description.replace(
416
+ '{{description}}',
417
+ description,
418
+ );
419
+ return stringToElement(html);
420
+ },
421
+
422
+ /**
423
+ * Renders an option group with header
424
+ */
425
+ optionGroup: (
426
+ label: string,
427
+ optionsHtml: string,
428
+ config: KTSelectConfigInterface,
429
+ ): HTMLElement => {
430
+ let html = getTemplateStrings(config)
431
+ .optionGroup.replace(/{{label}}/g, label)
432
+ .replace('{{optionsHtml}}', optionsHtml);
433
+ return stringToElement(html);
434
+ },
435
+
436
+ /**
437
+ * Renders the search input
438
+ */
439
+ search: (config: KTSelectConfigInterface): HTMLElement => {
440
+ let html = getTemplateStrings(config).search.replace(
441
+ '{{searchPlaceholder}}',
442
+ config.searchPlaceholder || 'Search...',
443
+ );
444
+ return stringToElement(html);
445
+ },
446
+
447
+ /**
448
+ * Renders the no results message
449
+ */
450
+ noResults: (config: KTSelectConfigInterface): HTMLElement => {
451
+ let html = getTemplateStrings(config).noResults.replace(
452
+ '{{searchNotFoundText}}',
453
+ config.searchNotFoundText || 'No results found',
454
+ );
455
+ return stringToElement(html);
456
+ },
457
+
458
+ /**
459
+ * Renders the loading state
460
+ */
461
+ loading: (
462
+ config: KTSelectConfigInterface,
463
+ loadingMessage: string,
464
+ ): HTMLElement => {
465
+ let html = getTemplateStrings(config).loading.replace(
466
+ '{{loadingMessage}}',
467
+ loadingMessage || 'Loading options...',
468
+ );
469
+ return stringToElement(html);
470
+ },
471
+
472
+ /**
473
+ * Renders a tag for multi-select
474
+ */
475
+ tag: (
476
+ option: KTSelectOption,
477
+ config: KTSelectConfigInterface,
478
+ ): HTMLElement => {
479
+ // Escape HTML characters for aria-label to prevent HTML injection
480
+ const escapeHTML = (str: string) => {
481
+ return str.replace(/[&<>"']/g, (match) => {
482
+ const escapeMap: Record<string, string> = {
483
+ '&': '&amp;',
484
+ '<': '&lt;',
485
+ '>': '&gt;',
486
+ '"': '&quot;',
487
+ "'": '&#39;',
488
+ };
489
+ return escapeMap[match];
490
+ });
491
+ };
492
+
493
+ // Ensure we have plain text for the aria-label
494
+ const safeTitle = escapeHTML(option.title);
495
+ let html = getTemplateStrings(config)
496
+ .tag.replace('{{title}}', option.title)
497
+ .replace('{{id}}', option.id)
498
+ .replace('{{safeTitle}}', safeTitle);
499
+ return stringToElement(html);
500
+ },
501
+
502
+ /**
503
+ * Formats the display of selected values
504
+ */
505
+ selectedDisplay: (
506
+ selectedOptions: KTSelectOption[],
507
+ config: KTSelectConfigInterface,
508
+ ): string => {
509
+ if (!selectedOptions || selectedOptions.length === 0) {
510
+ return config.placeholder || 'Select...';
511
+ }
512
+
513
+ if (config.multiple) {
514
+ if (
515
+ config.renderSelected &&
516
+ typeof config.renderSelected === 'function'
517
+ ) {
518
+ return config.renderSelected(selectedOptions);
519
+ }
520
+
521
+ if (config.showSelectedCount) {
522
+ const count = selectedOptions.length;
523
+ return `${count} ${count === 1 ? 'item' : 'items'} selected`;
524
+ }
525
+
526
+ return selectedOptions.map((option) => option.title).join(', ');
527
+ } else {
528
+ return selectedOptions[0].title;
529
+ }
530
+ },
531
+ };
@@ -0,0 +1,36 @@
1
+ /**
2
+ * KTUI - Free & Open-Source Tailwind UI Components by Keenthemes
3
+ * Copyright 2025 by Keenthemes Inc
4
+ * @version: 1.0.0
5
+ */
6
+ /**
7
+ * Common type interfaces for the KTSelect component
8
+ */
9
+
10
+ /**
11
+ * Select mode options
12
+ */
13
+ export enum SelectMode {
14
+ TAGS = 'tags',
15
+ COMBOBOX = 'combobox',
16
+ }
17
+
18
+ export interface KTSelectOption {
19
+ id: string;
20
+ title: string;
21
+ selected?: boolean;
22
+ description?: string;
23
+ icon?: string;
24
+ disabled?: boolean;
25
+ }
26
+
27
+ export interface KTSelectOptionData {
28
+ [key: string]: any;
29
+ }
30
+
31
+ export interface KTSelectState {
32
+ getSelectedOptions(): string[];
33
+ setSelectedOptions(value: string | string[]): void;
34
+ toggleSelectedOptions(value: string): void;
35
+ isSelected(value: string): boolean;
36
+ }