tekivex-ui 2.5.15 → 2.6.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 (395) hide show
  1. package/dist/charts.cjs +1 -1
  2. package/dist/charts.js +22 -553
  3. package/dist/chunk-B3ph66Zb.js +1 -0
  4. package/dist/chunk-Bc16rJT-.js +1 -0
  5. package/dist/chunk-Dike2DLU.js +3 -0
  6. package/dist/chunk-DjxOP8W4.js +1 -0
  7. package/dist/chunk-DkoFTL1O.js +1 -0
  8. package/dist/chunk-DmRB1Blb.js +1 -0
  9. package/dist/chunk-DnCXUUx5.js +1 -0
  10. package/dist/chunk-LWkKqC8d.js +1 -0
  11. package/dist/chunk-PJ50l0JC.js +1 -0
  12. package/dist/headless.cjs +1 -1
  13. package/dist/headless.js +1 -442
  14. package/dist/i18n.cjs +1 -1
  15. package/dist/i18n.js +1 -733
  16. package/dist/index.cjs +1 -152
  17. package/dist/index.d.ts +4 -2
  18. package/dist/index.js +429 -16786
  19. package/dist/quantum.cjs +1 -89
  20. package/dist/quantum.js +74 -2551
  21. package/dist/realtime.cjs +1 -23
  22. package/dist/realtime.js +1 -804
  23. package/dist/src/a11y/index.d.ts +0 -1
  24. package/dist/src/charts/TkxAreaChart.d.ts +0 -5
  25. package/dist/src/charts/TkxBarChart.d.ts +0 -3
  26. package/dist/src/charts/TkxDonutChart.d.ts +0 -5
  27. package/dist/src/charts/TkxLineChart.d.ts +0 -1
  28. package/dist/src/charts/TkxPieChart.d.ts +0 -3
  29. package/dist/src/charts/TkxRadarChart.d.ts +0 -3
  30. package/dist/src/charts/TkxScatterChart.d.ts +0 -2
  31. package/dist/src/charts/index.d.ts +0 -1
  32. package/dist/src/charts/shared.d.ts +0 -3
  33. package/dist/src/components/TkxAIChatBubble.d.ts +0 -9
  34. package/dist/src/components/TkxAIConfidenceBar.d.ts +0 -6
  35. package/dist/src/components/TkxAIThinking.d.ts +0 -6
  36. package/dist/src/components/TkxAccordion.d.ts +0 -1
  37. package/dist/src/components/TkxAffix.d.ts +0 -1
  38. package/dist/src/components/TkxAlert.d.ts +0 -1
  39. package/dist/src/components/TkxAnchor.d.ts +0 -1
  40. package/dist/src/components/TkxAppBar.d.ts +0 -1
  41. package/dist/src/components/TkxAutocomplete.d.ts +0 -1
  42. package/dist/src/components/TkxAvatar.d.ts +0 -1
  43. package/dist/src/components/TkxBadge.d.ts +0 -1
  44. package/dist/src/components/TkxBottomNav.d.ts +0 -1
  45. package/dist/src/components/TkxBreadcrumb.d.ts +0 -1
  46. package/dist/src/components/TkxButton.d.ts +0 -1
  47. package/dist/src/components/TkxCard.d.ts +0 -1
  48. package/dist/src/components/TkxCarousel.d.ts +0 -1
  49. package/dist/src/components/TkxCascader.d.ts +0 -1
  50. package/dist/src/components/TkxChat.d.ts +0 -1
  51. package/dist/src/components/TkxCheckbox.d.ts +0 -1
  52. package/dist/src/components/TkxClock.d.ts +0 -1
  53. package/dist/src/components/TkxColorPicker.d.ts +0 -1
  54. package/dist/src/components/TkxCommand.d.ts +0 -1
  55. package/dist/src/components/TkxConfigProvider.d.ts +0 -30
  56. package/dist/src/components/TkxDataGrid.d.ts +0 -15
  57. package/dist/src/components/TkxDatePicker.d.ts +0 -1
  58. package/dist/src/components/TkxDivider.d.ts +0 -1
  59. package/dist/src/components/TkxDrawer.d.ts +0 -1
  60. package/dist/src/components/TkxDropdown.d.ts +0 -1
  61. package/dist/src/components/TkxEmpty.d.ts +0 -1
  62. package/dist/src/components/TkxFileUpload.d.ts +0 -1
  63. package/dist/src/components/TkxForm.d.ts +0 -35
  64. package/dist/src/components/TkxIcon.d.ts +0 -1
  65. package/dist/src/components/TkxImage.d.ts +0 -1
  66. package/dist/src/components/TkxInput.d.ts +1 -1
  67. package/dist/src/components/TkxLayout.d.ts +0 -22
  68. package/dist/src/components/TkxList.d.ts +0 -1
  69. package/dist/src/components/TkxLiveFeed.d.ts +0 -1
  70. package/dist/src/components/TkxLiveLog.d.ts +0 -1
  71. package/dist/src/components/TkxLiveMetrics.d.ts +0 -1
  72. package/dist/src/components/TkxLogo.d.ts +0 -1
  73. package/dist/src/components/TkxMarkdown.d.ts +0 -10
  74. package/dist/src/components/TkxMasonry.d.ts +0 -1
  75. package/dist/src/components/TkxMentions.d.ts +0 -1
  76. package/dist/src/components/TkxMenu.d.ts +0 -1
  77. package/dist/src/components/TkxModal.d.ts +0 -1
  78. package/dist/src/components/TkxNumberInput.d.ts +0 -1
  79. package/dist/src/components/TkxOTP.d.ts +0 -1
  80. package/dist/src/components/TkxOrgChart.d.ts +32 -0
  81. package/dist/src/components/TkxPagination.d.ts +0 -1
  82. package/dist/src/components/TkxPlayground.d.ts +0 -13
  83. package/dist/src/components/TkxPopover.d.ts +0 -1
  84. package/dist/src/components/TkxProgress.d.ts +0 -1
  85. package/dist/src/components/TkxQRCode.d.ts +0 -1
  86. package/dist/src/components/TkxQuantumForm.d.ts +0 -1
  87. package/dist/src/components/TkxRadio.d.ts +0 -1
  88. package/dist/src/components/TkxRating.d.ts +0 -1
  89. package/dist/src/components/TkxRealTimeChart.d.ts +0 -1
  90. package/dist/src/components/TkxResult.d.ts +0 -1
  91. package/dist/src/components/TkxRichTextDisplay.d.ts +0 -1
  92. package/dist/src/components/TkxSegmented.d.ts +0 -1
  93. package/dist/src/components/TkxSelect.d.ts +0 -3
  94. package/dist/src/components/TkxSkeleton.d.ts +0 -1
  95. package/dist/src/components/TkxSlider.d.ts +0 -1
  96. package/dist/src/components/TkxSnackbar.d.ts +0 -1
  97. package/dist/src/components/TkxSpeedDial.d.ts +0 -1
  98. package/dist/src/components/TkxSpin.d.ts +0 -1
  99. package/dist/src/components/TkxStatistic.d.ts +0 -1
  100. package/dist/src/components/TkxStepper.d.ts +0 -1
  101. package/dist/src/components/TkxTable.d.ts +0 -1
  102. package/dist/src/components/TkxTabs.d.ts +0 -1
  103. package/dist/src/components/TkxTag.d.ts +0 -1
  104. package/dist/src/components/TkxThemeBuilder.d.ts +0 -1
  105. package/dist/src/components/TkxTimeline.d.ts +0 -1
  106. package/dist/src/components/TkxToast.d.ts +0 -1
  107. package/dist/src/components/TkxToggle.d.ts +0 -1
  108. package/dist/src/components/TkxToolbar.d.ts +0 -1
  109. package/dist/src/components/TkxTooltip.d.ts +0 -1
  110. package/dist/src/components/TkxTour.d.ts +0 -1
  111. package/dist/src/components/TkxTransferList.d.ts +0 -1
  112. package/dist/src/components/TkxTreeView.d.ts +0 -1
  113. package/dist/src/components/TkxTypography.d.ts +0 -1
  114. package/dist/src/components/TkxVideoPlayer.d.ts +0 -1
  115. package/dist/src/components/TkxWatermark.d.ts +0 -1
  116. package/dist/src/components/index.d.ts +1 -1
  117. package/dist/src/engine/css.d.ts +0 -1
  118. package/dist/src/engine/index.d.ts +0 -1
  119. package/dist/src/engine/quantum-ai.d.ts +0 -73
  120. package/dist/src/engine/quantum.d.ts +0 -1
  121. package/dist/src/engine/security.d.ts +45 -9
  122. package/dist/src/engine/tkx.d.ts +0 -53
  123. package/dist/src/engine/wcag.d.ts +0 -1
  124. package/dist/src/headless/index.d.ts +0 -1
  125. package/dist/src/headless/useControllable.d.ts +0 -15
  126. package/dist/src/headless/useDebounce.d.ts +0 -12
  127. package/dist/src/headless/useDisclosure.d.ts +0 -13
  128. package/dist/src/headless/useFormState.d.ts +0 -13
  129. package/dist/src/headless/useInfiniteQuery.d.ts +0 -11
  130. package/dist/src/headless/useIntersectionObserver.d.ts +0 -10
  131. package/dist/src/headless/useListSelection.d.ts +0 -9
  132. package/dist/src/headless/useLocalStorage.d.ts +0 -8
  133. package/dist/src/headless/useMediaQuery.d.ts +0 -10
  134. package/dist/src/headless/useRovingTabIndex.d.ts +0 -15
  135. package/dist/src/headless/useSSE.d.ts +0 -9
  136. package/dist/src/headless/useThrottle.d.ts +0 -7
  137. package/dist/src/headless/useWebSocket.d.ts +0 -9
  138. package/dist/src/hooks/index.d.ts +0 -1
  139. package/dist/src/i18n/I18nProvider.d.ts +0 -1
  140. package/dist/src/i18n/index.d.ts +0 -1
  141. package/dist/src/quantum/index.d.ts +0 -1
  142. package/dist/src/realtime/index.d.ts +0 -1
  143. package/dist/src/themes/index.d.ts +0 -1
  144. package/package.json +5 -3
  145. package/dist/TkxForm-BaO4wvXt.js +0 -320
  146. package/dist/TkxForm-M6ttomry.cjs +0 -12
  147. package/dist/chunk-Bmb41Sf3.cjs +0 -1
  148. package/dist/hooks-6pRsPOyG.js +0 -58
  149. package/dist/hooks-mivgRljH.cjs +0 -1
  150. package/dist/index.d.ts.map +0 -1
  151. package/dist/src/a11y/index.d.ts.map +0 -1
  152. package/dist/src/charts/TkxAreaChart.d.ts.map +0 -1
  153. package/dist/src/charts/TkxBarChart.d.ts.map +0 -1
  154. package/dist/src/charts/TkxDonutChart.d.ts.map +0 -1
  155. package/dist/src/charts/TkxLineChart.d.ts.map +0 -1
  156. package/dist/src/charts/TkxPieChart.d.ts.map +0 -1
  157. package/dist/src/charts/TkxRadarChart.d.ts.map +0 -1
  158. package/dist/src/charts/TkxScatterChart.d.ts.map +0 -1
  159. package/dist/src/charts/index.d.ts.map +0 -1
  160. package/dist/src/charts/shared.d.ts.map +0 -1
  161. package/dist/src/components/TkxAIChatBubble.d.ts.map +0 -1
  162. package/dist/src/components/TkxAIConfidenceBar.d.ts.map +0 -1
  163. package/dist/src/components/TkxAIThinking.d.ts.map +0 -1
  164. package/dist/src/components/TkxAccordion.d.ts.map +0 -1
  165. package/dist/src/components/TkxAffix.d.ts.map +0 -1
  166. package/dist/src/components/TkxAlert.d.ts.map +0 -1
  167. package/dist/src/components/TkxAnchor.d.ts.map +0 -1
  168. package/dist/src/components/TkxAppBar.d.ts.map +0 -1
  169. package/dist/src/components/TkxAutocomplete.d.ts.map +0 -1
  170. package/dist/src/components/TkxAvatar.d.ts.map +0 -1
  171. package/dist/src/components/TkxBadge.d.ts.map +0 -1
  172. package/dist/src/components/TkxBottomNav.d.ts.map +0 -1
  173. package/dist/src/components/TkxBreadcrumb.d.ts.map +0 -1
  174. package/dist/src/components/TkxButton.d.ts.map +0 -1
  175. package/dist/src/components/TkxCard.d.ts.map +0 -1
  176. package/dist/src/components/TkxCarousel.d.ts.map +0 -1
  177. package/dist/src/components/TkxCascader.d.ts.map +0 -1
  178. package/dist/src/components/TkxChat.d.ts.map +0 -1
  179. package/dist/src/components/TkxCheckbox.d.ts.map +0 -1
  180. package/dist/src/components/TkxClock.d.ts.map +0 -1
  181. package/dist/src/components/TkxColorPicker.d.ts.map +0 -1
  182. package/dist/src/components/TkxCommand.d.ts.map +0 -1
  183. package/dist/src/components/TkxConfigProvider.d.ts.map +0 -1
  184. package/dist/src/components/TkxDataGrid.d.ts.map +0 -1
  185. package/dist/src/components/TkxDatePicker.d.ts.map +0 -1
  186. package/dist/src/components/TkxDivider.d.ts.map +0 -1
  187. package/dist/src/components/TkxDrawer.d.ts.map +0 -1
  188. package/dist/src/components/TkxDropdown.d.ts.map +0 -1
  189. package/dist/src/components/TkxEmpty.d.ts.map +0 -1
  190. package/dist/src/components/TkxFileUpload.d.ts.map +0 -1
  191. package/dist/src/components/TkxForm.d.ts.map +0 -1
  192. package/dist/src/components/TkxIcon.d.ts.map +0 -1
  193. package/dist/src/components/TkxImage.d.ts.map +0 -1
  194. package/dist/src/components/TkxInput.d.ts.map +0 -1
  195. package/dist/src/components/TkxLayout.d.ts.map +0 -1
  196. package/dist/src/components/TkxList.d.ts.map +0 -1
  197. package/dist/src/components/TkxLiveFeed.d.ts.map +0 -1
  198. package/dist/src/components/TkxLiveLog.d.ts.map +0 -1
  199. package/dist/src/components/TkxLiveMetrics.d.ts.map +0 -1
  200. package/dist/src/components/TkxLogo.d.ts.map +0 -1
  201. package/dist/src/components/TkxMarkdown.d.ts.map +0 -1
  202. package/dist/src/components/TkxMasonry.d.ts.map +0 -1
  203. package/dist/src/components/TkxMentions.d.ts.map +0 -1
  204. package/dist/src/components/TkxMenu.d.ts.map +0 -1
  205. package/dist/src/components/TkxModal.d.ts.map +0 -1
  206. package/dist/src/components/TkxNumberInput.d.ts.map +0 -1
  207. package/dist/src/components/TkxOTP.d.ts.map +0 -1
  208. package/dist/src/components/TkxPagination.d.ts.map +0 -1
  209. package/dist/src/components/TkxPlayground.d.ts.map +0 -1
  210. package/dist/src/components/TkxPopover.d.ts.map +0 -1
  211. package/dist/src/components/TkxProgress.d.ts.map +0 -1
  212. package/dist/src/components/TkxQRCode.d.ts.map +0 -1
  213. package/dist/src/components/TkxQuantumForm.d.ts.map +0 -1
  214. package/dist/src/components/TkxRadio.d.ts.map +0 -1
  215. package/dist/src/components/TkxRating.d.ts.map +0 -1
  216. package/dist/src/components/TkxRealTimeChart.d.ts.map +0 -1
  217. package/dist/src/components/TkxResult.d.ts.map +0 -1
  218. package/dist/src/components/TkxRichTextDisplay.d.ts.map +0 -1
  219. package/dist/src/components/TkxSegmented.d.ts.map +0 -1
  220. package/dist/src/components/TkxSelect.d.ts.map +0 -1
  221. package/dist/src/components/TkxSkeleton.d.ts.map +0 -1
  222. package/dist/src/components/TkxSlider.d.ts.map +0 -1
  223. package/dist/src/components/TkxSnackbar.d.ts.map +0 -1
  224. package/dist/src/components/TkxSpeedDial.d.ts.map +0 -1
  225. package/dist/src/components/TkxSpin.d.ts.map +0 -1
  226. package/dist/src/components/TkxStatistic.d.ts.map +0 -1
  227. package/dist/src/components/TkxStepper.d.ts.map +0 -1
  228. package/dist/src/components/TkxTable.d.ts.map +0 -1
  229. package/dist/src/components/TkxTabs.d.ts.map +0 -1
  230. package/dist/src/components/TkxTag.d.ts.map +0 -1
  231. package/dist/src/components/TkxThemeBuilder.d.ts.map +0 -1
  232. package/dist/src/components/TkxTimeline.d.ts.map +0 -1
  233. package/dist/src/components/TkxToast.d.ts.map +0 -1
  234. package/dist/src/components/TkxToggle.d.ts.map +0 -1
  235. package/dist/src/components/TkxToolbar.d.ts.map +0 -1
  236. package/dist/src/components/TkxTooltip.d.ts.map +0 -1
  237. package/dist/src/components/TkxTour.d.ts.map +0 -1
  238. package/dist/src/components/TkxTransferList.d.ts.map +0 -1
  239. package/dist/src/components/TkxTreeView.d.ts.map +0 -1
  240. package/dist/src/components/TkxTypography.d.ts.map +0 -1
  241. package/dist/src/components/TkxVideoPlayer.d.ts.map +0 -1
  242. package/dist/src/components/TkxWatermark.d.ts.map +0 -1
  243. package/dist/src/components/index.d.ts.map +0 -1
  244. package/dist/src/engine/css.d.ts.map +0 -1
  245. package/dist/src/engine/index.d.ts.map +0 -1
  246. package/dist/src/engine/quantum-ai.d.ts.map +0 -1
  247. package/dist/src/engine/quantum.d.ts.map +0 -1
  248. package/dist/src/engine/security.d.ts.map +0 -1
  249. package/dist/src/engine/tkx.d.ts.map +0 -1
  250. package/dist/src/engine/wcag.d.ts.map +0 -1
  251. package/dist/src/headless/index.d.ts.map +0 -1
  252. package/dist/src/headless/useControllable.d.ts.map +0 -1
  253. package/dist/src/headless/useDebounce.d.ts.map +0 -1
  254. package/dist/src/headless/useDisclosure.d.ts.map +0 -1
  255. package/dist/src/headless/useFormState.d.ts.map +0 -1
  256. package/dist/src/headless/useInfiniteQuery.d.ts.map +0 -1
  257. package/dist/src/headless/useIntersectionObserver.d.ts.map +0 -1
  258. package/dist/src/headless/useListSelection.d.ts.map +0 -1
  259. package/dist/src/headless/useLocalStorage.d.ts.map +0 -1
  260. package/dist/src/headless/useMediaQuery.d.ts.map +0 -1
  261. package/dist/src/headless/useRovingTabIndex.d.ts.map +0 -1
  262. package/dist/src/headless/useSSE.d.ts.map +0 -1
  263. package/dist/src/headless/useThrottle.d.ts.map +0 -1
  264. package/dist/src/headless/useWebSocket.d.ts.map +0 -1
  265. package/dist/src/hooks/index.d.ts.map +0 -1
  266. package/dist/src/i18n/I18nProvider.d.ts.map +0 -1
  267. package/dist/src/i18n/index.d.ts.map +0 -1
  268. package/dist/src/quantum/index.d.ts.map +0 -1
  269. package/dist/src/realtime/index.d.ts.map +0 -1
  270. package/dist/src/themes/index.d.ts.map +0 -1
  271. package/dist/themes-BbJanqiC.js +0 -498
  272. package/dist/themes-CMq2vWXj.cjs +0 -2
  273. package/dist/tkx-BoP5V5zy.cjs +0 -4
  274. package/dist/tkx-mOKMzvUK.js +0 -1174
  275. package/src/a11y/index.tsx +0 -87
  276. package/src/charts/TkxAreaChart.tsx +0 -121
  277. package/src/charts/TkxBarChart.tsx +0 -117
  278. package/src/charts/TkxDonutChart.tsx +0 -164
  279. package/src/charts/TkxLineChart.tsx +0 -137
  280. package/src/charts/TkxPieChart.tsx +0 -103
  281. package/src/charts/TkxRadarChart.tsx +0 -92
  282. package/src/charts/TkxScatterChart.tsx +0 -104
  283. package/src/charts/index.ts +0 -22
  284. package/src/charts/shared.ts +0 -47
  285. package/src/components/TkxAIChatBubble.tsx +0 -256
  286. package/src/components/TkxAIConfidenceBar.tsx +0 -133
  287. package/src/components/TkxAIThinking.tsx +0 -193
  288. package/src/components/TkxAccordion.tsx +0 -590
  289. package/src/components/TkxAffix.tsx +0 -140
  290. package/src/components/TkxAlert.tsx +0 -94
  291. package/src/components/TkxAnchor.tsx +0 -195
  292. package/src/components/TkxAppBar.tsx +0 -262
  293. package/src/components/TkxAutocomplete.tsx +0 -455
  294. package/src/components/TkxAvatar.tsx +0 -103
  295. package/src/components/TkxBadge.tsx +0 -75
  296. package/src/components/TkxBottomNav.tsx +0 -241
  297. package/src/components/TkxBreadcrumb.tsx +0 -324
  298. package/src/components/TkxButton.tsx +0 -155
  299. package/src/components/TkxCard.tsx +0 -96
  300. package/src/components/TkxCarousel.tsx +0 -554
  301. package/src/components/TkxCascader.tsx +0 -278
  302. package/src/components/TkxChat.tsx +0 -356
  303. package/src/components/TkxCheckbox.tsx +0 -220
  304. package/src/components/TkxClock.tsx +0 -603
  305. package/src/components/TkxColorPicker.tsx +0 -635
  306. package/src/components/TkxCommand.tsx +0 -646
  307. package/src/components/TkxConfigProvider.tsx +0 -460
  308. package/src/components/TkxDataGrid.tsx +0 -941
  309. package/src/components/TkxDatePicker.tsx +0 -1625
  310. package/src/components/TkxDivider.tsx +0 -51
  311. package/src/components/TkxDrawer.tsx +0 -236
  312. package/src/components/TkxDropdown.tsx +0 -804
  313. package/src/components/TkxEmpty.tsx +0 -221
  314. package/src/components/TkxFileUpload.tsx +0 -373
  315. package/src/components/TkxForm.tsx +0 -683
  316. package/src/components/TkxIcon.tsx +0 -685
  317. package/src/components/TkxImage.tsx +0 -279
  318. package/src/components/TkxInput.tsx +0 -103
  319. package/src/components/TkxLayout.tsx +0 -649
  320. package/src/components/TkxList.tsx +0 -244
  321. package/src/components/TkxLiveFeed.tsx +0 -331
  322. package/src/components/TkxLiveLog.tsx +0 -472
  323. package/src/components/TkxLiveMetrics.tsx +0 -315
  324. package/src/components/TkxLogo.tsx +0 -299
  325. package/src/components/TkxMarkdown.tsx +0 -855
  326. package/src/components/TkxMasonry.tsx +0 -178
  327. package/src/components/TkxMentions.tsx +0 -212
  328. package/src/components/TkxMenu.tsx +0 -1044
  329. package/src/components/TkxModal.tsx +0 -122
  330. package/src/components/TkxNumberInput.tsx +0 -410
  331. package/src/components/TkxOTP.tsx +0 -297
  332. package/src/components/TkxPagination.tsx +0 -390
  333. package/src/components/TkxPlayground.tsx +0 -845
  334. package/src/components/TkxPopover.tsx +0 -297
  335. package/src/components/TkxProgress.tsx +0 -114
  336. package/src/components/TkxQRCode.tsx +0 -176
  337. package/src/components/TkxQuantumForm.tsx +0 -594
  338. package/src/components/TkxRadio.tsx +0 -286
  339. package/src/components/TkxRating.tsx +0 -288
  340. package/src/components/TkxRealTimeChart.tsx +0 -383
  341. package/src/components/TkxResult.tsx +0 -130
  342. package/src/components/TkxRichTextDisplay.tsx +0 -396
  343. package/src/components/TkxSegmented.tsx +0 -171
  344. package/src/components/TkxSelect.tsx +0 -1130
  345. package/src/components/TkxSkeleton.tsx +0 -107
  346. package/src/components/TkxSlider.tsx +0 -495
  347. package/src/components/TkxSnackbar.tsx +0 -316
  348. package/src/components/TkxSpeedDial.tsx +0 -397
  349. package/src/components/TkxSpin.tsx +0 -263
  350. package/src/components/TkxStatistic.tsx +0 -263
  351. package/src/components/TkxStepper.tsx +0 -487
  352. package/src/components/TkxTable.tsx +0 -424
  353. package/src/components/TkxTabs.tsx +0 -126
  354. package/src/components/TkxTag.tsx +0 -321
  355. package/src/components/TkxThemeBuilder.tsx +0 -687
  356. package/src/components/TkxTimeline.tsx +0 -305
  357. package/src/components/TkxToast.tsx +0 -287
  358. package/src/components/TkxToggle.tsx +0 -95
  359. package/src/components/TkxToolbar.tsx +0 -262
  360. package/src/components/TkxTooltip.tsx +0 -85
  361. package/src/components/TkxTour.tsx +0 -241
  362. package/src/components/TkxTransferList.tsx +0 -489
  363. package/src/components/TkxTreeView.tsx +0 -423
  364. package/src/components/TkxTypography.tsx +0 -267
  365. package/src/components/TkxVideoPlayer.tsx +0 -1015
  366. package/src/components/TkxWatermark.tsx +0 -145
  367. package/src/components/index.ts +0 -80
  368. package/src/engine/css.ts +0 -126
  369. package/src/engine/index.ts +0 -12
  370. package/src/engine/quantum-ai.ts +0 -1045
  371. package/src/engine/quantum.ts +0 -207
  372. package/src/engine/security.ts +0 -232
  373. package/src/engine/tkx.ts +0 -1084
  374. package/src/engine/wcag.ts +0 -276
  375. package/src/headless/index.ts +0 -52
  376. package/src/headless/useControllable.ts +0 -42
  377. package/src/headless/useDebounce.ts +0 -37
  378. package/src/headless/useDisclosure.ts +0 -30
  379. package/src/headless/useFormState.ts +0 -113
  380. package/src/headless/useInfiniteQuery.ts +0 -155
  381. package/src/headless/useIntersectionObserver.ts +0 -53
  382. package/src/headless/useListSelection.ts +0 -103
  383. package/src/headless/useLocalStorage.ts +0 -48
  384. package/src/headless/useMediaQuery.ts +0 -39
  385. package/src/headless/useRovingTabIndex.ts +0 -86
  386. package/src/headless/useSSE.ts +0 -167
  387. package/src/headless/useThrottle.ts +0 -48
  388. package/src/headless/useWebSocket.ts +0 -231
  389. package/src/hooks/index.ts +0 -122
  390. package/src/i18n/I18nProvider.tsx +0 -36
  391. package/src/i18n/index.ts +0 -877
  392. package/src/quantum/index.ts +0 -39
  393. package/src/realtime/index.ts +0 -21
  394. package/src/styles/global.css +0 -167
  395. package/src/themes/index.ts +0 -294
@@ -1,1130 +0,0 @@
1
- 'use client';
2
-
3
- import {
4
- useState,
5
- useRef,
6
- useEffect,
7
- useCallback,
8
- useId,
9
- type ReactNode,
10
- type CSSProperties,
11
- type KeyboardEvent,
12
- } from 'react';
13
- import { createPortal } from 'react-dom';
14
- import { useTheme } from '../themes';
15
- import { sanitizeString } from '../engine/security';
16
- import { tkx, cx } from '../engine/tkx';
17
-
18
- // ── Types ──────────────────────────────────────────────────────────────────────
19
-
20
- export type SelectSize = 'sm' | 'md' | 'lg';
21
-
22
- export interface SelectOption {
23
- value: string;
24
- label: string;
25
- group?: string;
26
- disabled?: boolean;
27
- icon?: ReactNode;
28
- description?: string;
29
- }
30
-
31
- export interface TkxSelectProps {
32
- options: SelectOption[];
33
- value?: string | string[];
34
- defaultValue?: string | string[];
35
- placeholder?: string;
36
- size?: SelectSize;
37
- isDisabled?: boolean;
38
- isInvalid?: boolean;
39
- label?: string;
40
- hint?: string;
41
- errorMessage?: string;
42
- multiple?: boolean;
43
- searchable?: boolean;
44
- clearable?: boolean;
45
- isLoading?: boolean;
46
- onChange?: (value: string | string[]) => void;
47
- renderOption?: (option: SelectOption, isSelected: boolean) => ReactNode;
48
- maxMenuHeight?: number;
49
- /** Enable virtual scrolling for the dropdown. Defaults to auto (enabled when 100+ options). */
50
- virtualScroll?: boolean;
51
- /** Fixed option height in pixels for virtual scroll calculations. Default: 36 */
52
- optionHeight?: number;
53
- id?: string;
54
- className?: string;
55
- style?: CSSProperties;
56
- }
57
-
58
- // ── Helpers ────────────────────────────────────────────────────────────────────
59
-
60
- const SIZE_MAP: Record<SelectSize, { py: string; px: string; fontSize: string; iconSize: number; tagPy: string; tagPx: string }> = {
61
- sm: { py: '6px', px: '10px', fontSize: '13px', iconSize: 14, tagPy: '1px', tagPx: '6px' },
62
- md: { py: '9px', px: '12px', fontSize: '14px', iconSize: 16, tagPy: '2px', tagPx: '8px' },
63
- lg: { py: '12px', px: '14px', fontSize: '15px', iconSize: 18, tagPy: '3px', tagPx: '10px' },
64
- };
65
-
66
- function toArray(v: string | string[] | undefined): string[] {
67
- if (v === undefined) return [];
68
- return Array.isArray(v) ? v : [v];
69
- }
70
-
71
- // ── Portal Dropdown positioning ────────────────────────────────────────────────
72
-
73
- interface DropdownRect {
74
- top: number;
75
- left: number;
76
- width: number;
77
- placement: 'below' | 'above';
78
- }
79
-
80
- function calcDropdownRect(
81
- triggerEl: HTMLElement,
82
- dropdownHeight: number,
83
- ): DropdownRect {
84
- const rect = triggerEl.getBoundingClientRect();
85
- const viewportH = window.innerHeight;
86
- const gap = 6;
87
- const spaceBelow = viewportH - rect.bottom - gap;
88
- const spaceAbove = rect.top - gap;
89
- const placement: 'below' | 'above' =
90
- spaceBelow >= Math.min(dropdownHeight, 200) || spaceBelow >= spaceAbove
91
- ? 'below'
92
- : 'above';
93
-
94
- return {
95
- top:
96
- placement === 'below'
97
- ? rect.bottom + window.scrollY + gap
98
- : rect.top + window.scrollY - gap - Math.min(dropdownHeight, 280),
99
- left: rect.left + window.scrollX,
100
- width: rect.width,
101
- placement,
102
- };
103
- }
104
-
105
- // ── Spinner ────────────────────────────────────────────────────────────────────
106
-
107
- function Spinner({ size, color }: { size: number; color: string }) {
108
- return (
109
- <svg
110
- width={size}
111
- height={size}
112
- viewBox="0 0 24 24"
113
- fill="none"
114
- stroke={color}
115
- strokeWidth="2.5"
116
- strokeLinecap="round"
117
- aria-hidden="true"
118
- style={{
119
- animation: 'tkx-spin 0.7s linear infinite',
120
- }}
121
- >
122
- <style>{`@keyframes tkx-spin{to{transform:rotate(360deg)}}`}</style>
123
- <path d="M12 2a10 10 0 0 1 10 10" />
124
- </svg>
125
- );
126
- }
127
-
128
- // ── Main Component ─────────────────────────────────────────────────────────────
129
-
130
- export function TkxSelect({
131
- options,
132
- value: valueProp,
133
- defaultValue,
134
- placeholder = 'Select an option…',
135
- size = 'md',
136
- isDisabled = false,
137
- isInvalid = false,
138
- label,
139
- hint,
140
- errorMessage,
141
- multiple = false,
142
- searchable = false,
143
- clearable = false,
144
- isLoading = false,
145
- onChange,
146
- renderOption,
147
- maxMenuHeight = 280,
148
- virtualScroll,
149
- optionHeight = 36,
150
- id: idProp,
151
- className,
152
- style,
153
- }: TkxSelectProps) {
154
- const theme = useTheme();
155
- const autoId = useId();
156
- const id = idProp ?? autoId;
157
- const listboxId = `${id}-listbox`;
158
- const hintId = `${id}-hint`;
159
- const errorId = `${id}-error`;
160
-
161
- const isControlled = valueProp !== undefined;
162
- const [internalValue, setInternalValue] = useState<string[]>(
163
- toArray(defaultValue),
164
- );
165
-
166
- const selectedValues = isControlled ? toArray(valueProp) : internalValue;
167
-
168
- const [isOpen, setIsOpen] = useState(false);
169
- const [search, setSearch] = useState('');
170
- const [activeIndex, setActiveIndex] = useState(-1);
171
- const [dropdownRect, setDropdownRect] = useState<DropdownRect | null>(null);
172
- const [typeahead, setTypeahead] = useState('');
173
- const typeaheadTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
174
-
175
- const triggerRef = useRef<HTMLButtonElement>(null);
176
- const searchInputRef = useRef<HTMLInputElement>(null);
177
- const dropdownRef = useRef<HTMLDivElement>(null);
178
- const listRef = useRef<HTMLDivElement>(null);
179
-
180
- const sz = SIZE_MAP[size];
181
- const hasError = isInvalid || !!errorMessage;
182
-
183
- // ── Virtual scroll for options ─────────────────────────────────────────
184
-
185
- const optionsListRef = useRef<HTMLDivElement>(null);
186
- const [optScrollTop, setOptScrollTop] = useState(0);
187
- const [optContainerHeight, setOptContainerHeight] = useState(0);
188
-
189
- const handleOptScroll = useCallback(() => {
190
- if (!optionsListRef.current) return;
191
- setOptScrollTop(optionsListRef.current.scrollTop);
192
- }, []);
193
-
194
- useEffect(() => {
195
- if (!isOpen) {
196
- setOptScrollTop(0);
197
- return;
198
- }
199
- const el = optionsListRef.current;
200
- if (!el) return;
201
- setOptContainerHeight(el.clientHeight);
202
- const ro = new ResizeObserver(() => {
203
- setOptContainerHeight(el.clientHeight);
204
- });
205
- ro.observe(el);
206
- return () => ro.disconnect();
207
- }, [isOpen]);
208
-
209
- // ── Filtered + grouped options ────────────────────────────────────────────
210
-
211
- const filteredOptions = searchable && search
212
- ? options.filter((o) =>
213
- o.label.toLowerCase().includes(search.toLowerCase()),
214
- )
215
- : options;
216
-
217
- const flatEnabled = filteredOptions.filter((o) => !o.disabled);
218
-
219
- const hasGroups = filteredOptions.some((o) => !!o.group);
220
- const isVirtualSelect =
221
- virtualScroll !== undefined
222
- ? virtualScroll
223
- : filteredOptions.length >= 100;
224
- // Only virtualize when we have a flat list (no groups) for simplicity
225
- const useVirtual = isVirtualSelect && !hasGroups;
226
-
227
- const OPTION_OVERSCAN = 8;
228
- const virtualTotalHeight = filteredOptions.length * optionHeight;
229
- const vStartIndex = useVirtual
230
- ? Math.max(0, Math.floor(optScrollTop / optionHeight) - OPTION_OVERSCAN)
231
- : 0;
232
- const vEndIndex = useVirtual
233
- ? Math.min(filteredOptions.length, Math.ceil((optScrollTop + optContainerHeight) / optionHeight) + OPTION_OVERSCAN)
234
- : filteredOptions.length;
235
- const visibleOptions = useVirtual ? filteredOptions.slice(vStartIndex, vEndIndex) : filteredOptions;
236
- const vOffsetY = vStartIndex * optionHeight;
237
-
238
- const groups = filteredOptions.reduce<Record<string, SelectOption[]>>(
239
- (acc, opt) => {
240
- const g = opt.group ?? '';
241
- if (!acc[g]) acc[g] = [];
242
- acc[g].push(opt);
243
- return acc;
244
- },
245
- {},
246
- );
247
-
248
- // ── Commit value ──────────────────────────────────────────────────────────
249
-
250
- const commitValue = useCallback(
251
- (val: string) => {
252
- let next: string[];
253
- if (multiple) {
254
- next = selectedValues.includes(val)
255
- ? selectedValues.filter((v) => v !== val)
256
- : [...selectedValues, val];
257
- } else {
258
- next = [val];
259
- }
260
-
261
- if (!isControlled) setInternalValue(next);
262
- onChange?.(multiple ? next : next[0] ?? '');
263
-
264
- if (!multiple) {
265
- setIsOpen(false);
266
- setSearch('');
267
- setActiveIndex(-1);
268
- triggerRef.current?.focus();
269
- }
270
- },
271
- [isControlled, multiple, onChange, selectedValues],
272
- );
273
-
274
- const removeTag = useCallback(
275
- (val: string, e: React.MouseEvent) => {
276
- e.stopPropagation();
277
- const next = selectedValues.filter((v) => v !== val);
278
- if (!isControlled) setInternalValue(next);
279
- onChange?.(multiple ? next : next[0] ?? '');
280
- },
281
- [isControlled, multiple, onChange, selectedValues],
282
- );
283
-
284
- const clearAll = useCallback(
285
- (e: React.MouseEvent) => {
286
- e.stopPropagation();
287
- if (!isControlled) setInternalValue([]);
288
- onChange?.(multiple ? [] : '');
289
- },
290
- [isControlled, multiple, onChange],
291
- );
292
-
293
- // ── Positioning ───────────────────────────────────────────────────────────
294
-
295
- const updatePosition = useCallback(() => {
296
- if (!triggerRef.current || !isOpen) return;
297
- setDropdownRect(calcDropdownRect(triggerRef.current, maxMenuHeight));
298
- }, [isOpen, maxMenuHeight]);
299
-
300
- useEffect(() => {
301
- if (!isOpen) return;
302
- updatePosition();
303
- window.addEventListener('scroll', updatePosition, true);
304
- window.addEventListener('resize', updatePosition);
305
- return () => {
306
- window.removeEventListener('scroll', updatePosition, true);
307
- window.removeEventListener('resize', updatePosition);
308
- };
309
- }, [isOpen, updatePosition]);
310
-
311
- // ── Outside click ─────────────────────────────────────────────────────────
312
-
313
- useEffect(() => {
314
- if (!isOpen) return;
315
- const handler = (e: PointerEvent) => {
316
- const target = e.target as Node;
317
- if (
318
- triggerRef.current?.contains(target) ||
319
- dropdownRef.current?.contains(target)
320
- )
321
- return;
322
- setIsOpen(false);
323
- setSearch('');
324
- };
325
- document.addEventListener('pointerdown', handler);
326
- return () => document.removeEventListener('pointerdown', handler);
327
- }, [isOpen]);
328
-
329
- // ── Focus search when open ────────────────────────────────────────────────
330
-
331
- useEffect(() => {
332
- if (isOpen && searchable) {
333
- setTimeout(() => searchInputRef.current?.focus(), 0);
334
- }
335
- }, [isOpen, searchable]);
336
-
337
- // ── Scroll active item into view ──────────────────────────────────────────
338
-
339
- useEffect(() => {
340
- if (!isOpen || activeIndex < 0) return;
341
- if (useVirtual && optionsListRef.current) {
342
- // For virtual scroll, compute position directly
343
- const itemTop = activeIndex * optionHeight;
344
- const itemBottom = itemTop + optionHeight;
345
- const el = optionsListRef.current;
346
- if (itemTop < el.scrollTop) {
347
- el.scrollTop = itemTop;
348
- } else if (itemBottom > el.scrollTop + el.clientHeight) {
349
- el.scrollTop = itemBottom - el.clientHeight;
350
- }
351
- } else {
352
- const el = listRef.current?.querySelector(
353
- `[data-idx="${activeIndex}"]`,
354
- ) as HTMLElement | null;
355
- el?.scrollIntoView({ block: 'nearest' });
356
- }
357
- }, [activeIndex, isOpen, useVirtual, optionHeight]);
358
-
359
- // ── Keyboard: trigger button ───────────────────────────────────────────────
360
-
361
- const handleTriggerKeyDown = (e: KeyboardEvent<HTMLButtonElement>) => {
362
- switch (e.key) {
363
- case 'Enter':
364
- case ' ':
365
- e.preventDefault();
366
- if (!isOpen) {
367
- openDropdown();
368
- } else if (activeIndex >= 0 && flatEnabled[activeIndex]) {
369
- commitValue(flatEnabled[activeIndex].value);
370
- }
371
- break;
372
- case 'Escape':
373
- e.preventDefault();
374
- setIsOpen(false);
375
- setSearch('');
376
- break;
377
- case 'ArrowDown':
378
- e.preventDefault();
379
- if (!isOpen) openDropdown();
380
- else setActiveIndex((i) => Math.min(i + 1, flatEnabled.length - 1));
381
- break;
382
- case 'ArrowUp':
383
- e.preventDefault();
384
- if (!isOpen) openDropdown();
385
- else setActiveIndex((i) => Math.max(i - 1, 0));
386
- break;
387
- case 'Home':
388
- e.preventDefault();
389
- if (isOpen) setActiveIndex(0);
390
- break;
391
- case 'End':
392
- e.preventDefault();
393
- if (isOpen) setActiveIndex(flatEnabled.length - 1);
394
- break;
395
- default:
396
- if (e.key.length === 1 && !e.ctrlKey && !e.metaKey) {
397
- if (!isOpen) openDropdown();
398
- handleTypeahead(e.key);
399
- }
400
- }
401
- };
402
-
403
- // ── Keyboard: search input ─────────────────────────────────────────────────
404
-
405
- const handleSearchKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
406
- switch (e.key) {
407
- case 'Escape':
408
- e.preventDefault();
409
- setIsOpen(false);
410
- setSearch('');
411
- triggerRef.current?.focus();
412
- break;
413
- case 'ArrowDown':
414
- e.preventDefault();
415
- setActiveIndex((i) => Math.min(i + 1, flatEnabled.length - 1));
416
- break;
417
- case 'ArrowUp':
418
- e.preventDefault();
419
- setActiveIndex((i) => Math.max(i - 1, 0));
420
- break;
421
- case 'Home':
422
- e.preventDefault();
423
- setActiveIndex(0);
424
- break;
425
- case 'End':
426
- e.preventDefault();
427
- setActiveIndex(flatEnabled.length - 1);
428
- break;
429
- case 'Enter':
430
- e.preventDefault();
431
- if (activeIndex >= 0 && flatEnabled[activeIndex]) {
432
- commitValue(flatEnabled[activeIndex].value);
433
- }
434
- break;
435
- }
436
- };
437
-
438
- // ── Typeahead ─────────────────────────────────────────────────────────────
439
-
440
- function handleTypeahead(char: string) {
441
- if (typeaheadTimer.current) clearTimeout(typeaheadTimer.current);
442
- const next = typeahead + char.toLowerCase();
443
- setTypeahead(next);
444
-
445
- const idx = flatEnabled.findIndex((o) =>
446
- o.label.toLowerCase().startsWith(next),
447
- );
448
- if (idx >= 0) setActiveIndex(idx);
449
-
450
- typeaheadTimer.current = setTimeout(() => setTypeahead(''), 800);
451
- }
452
-
453
- function openDropdown() {
454
- if (isDisabled || isLoading) return;
455
- setIsOpen(true);
456
- const startIdx = flatEnabled.findIndex((o) =>
457
- selectedValues.includes(o.value),
458
- );
459
- setActiveIndex(startIdx >= 0 ? startIdx : 0);
460
- }
461
-
462
- // ── Render helpers ────────────────────────────────────────────────────────
463
-
464
- const borderColor = hasError
465
- ? theme.danger
466
- : isOpen
467
- ? theme.primary
468
- : theme.border;
469
-
470
- const activeOptionId =
471
- activeIndex >= 0 && flatEnabled[activeIndex]
472
- ? `${id}-opt-${flatEnabled[activeIndex].value}`
473
- : undefined;
474
-
475
- const describedBy =
476
- [hint && hintId, hasError && errorId].filter(Boolean).join(' ') ||
477
- undefined;
478
-
479
- // Tags displayed in trigger when multiple
480
- const selectedOptionObjects = selectedValues
481
- .map((v) => options.find((o) => o.value === v))
482
- .filter(Boolean) as SelectOption[];
483
-
484
- // ── Dropdown element (portalled) ──────────────────────────────────────────
485
-
486
- const dropdownEl = isOpen && dropdownRect
487
- ? createPortal(
488
- <div
489
- ref={dropdownRef}
490
- role="listbox"
491
- id={listboxId}
492
- aria-label={label ? sanitizeString(label) : 'Options'}
493
- aria-multiselectable={multiple}
494
- style={{
495
- position: 'absolute',
496
- top: dropdownRect.top,
497
- left: dropdownRect.left,
498
- width: dropdownRect.width,
499
- zIndex: 9999,
500
- backgroundColor: theme.surface,
501
- border: `1.5px solid ${theme.border}`,
502
- borderRadius: 10,
503
- boxShadow: `0 8px 32px rgba(0,0,0,0.28), 0 2px 8px rgba(0,0,0,0.14)`,
504
- overflow: 'hidden',
505
- minWidth: dropdownRect.width,
506
- maxHeight: maxMenuHeight,
507
- display: 'flex',
508
- flexDirection: 'column',
509
- }}
510
- >
511
- {/* Search */}
512
- {searchable && (
513
- <div
514
- style={{
515
- padding: '8px 10px',
516
- borderBottom: `1px solid ${theme.border}`,
517
- flexShrink: 0,
518
- display: 'flex',
519
- alignItems: 'center',
520
- gap: 6,
521
- }}
522
- >
523
- <svg
524
- width="14"
525
- height="14"
526
- viewBox="0 0 24 24"
527
- fill="none"
528
- stroke={theme.textMuted}
529
- strokeWidth="2"
530
- aria-hidden="true"
531
- style={{ flexShrink: 0 }}
532
- >
533
- <circle cx="11" cy="11" r="8" />
534
- <path d="M21 21l-4.35-4.35" />
535
- </svg>
536
- <input
537
- ref={searchInputRef}
538
- type="text"
539
- value={search}
540
- onChange={(e) => {
541
- setSearch(e.target.value);
542
- setActiveIndex(0);
543
- }}
544
- onKeyDown={handleSearchKeyDown}
545
- placeholder="Search…"
546
- aria-label="Search options"
547
- style={{
548
- border: 'none',
549
- outline: 'none',
550
- background: 'transparent',
551
- color: theme.text,
552
- fontSize: sz.fontSize,
553
- fontFamily: 'inherit',
554
- width: '100%',
555
- }}
556
- />
557
- </div>
558
- )}
559
-
560
- {/* Options list */}
561
- <div
562
- ref={(el) => {
563
- (listRef as React.MutableRefObject<HTMLDivElement | null>).current = el;
564
- (optionsListRef as React.MutableRefObject<HTMLDivElement | null>).current = el;
565
- }}
566
- onScroll={useVirtual ? handleOptScroll : undefined}
567
- style={{
568
- overflowY: 'auto',
569
- flexGrow: 1,
570
- maxHeight: maxMenuHeight - (searchable ? 48 : 0),
571
- }}
572
- >
573
- {useVirtual ? (
574
- /* Virtualized flat list (no groups) */
575
- <div style={{ height: virtualTotalHeight, position: 'relative' }}>
576
- <div style={{ position: 'absolute', top: vOffsetY, left: 0, right: 0 }}>
577
- {visibleOptions.map((opt) => {
578
- const flatIdx = flatEnabled.indexOf(opt);
579
- const isActive = flatIdx === activeIndex;
580
- const isSelected = selectedValues.includes(opt.value);
581
-
582
- const optionContent = renderOption ? (
583
- renderOption(opt, isSelected)
584
- ) : (
585
- <span
586
- style={{
587
- display: 'flex',
588
- flexDirection: 'column',
589
- flex: 1,
590
- minWidth: 0,
591
- }}
592
- >
593
- <span
594
- style={{
595
- display: 'flex',
596
- alignItems: 'center',
597
- gap: 8,
598
- }}
599
- >
600
- {opt.icon && (
601
- <span style={{ flexShrink: 0, display: 'flex' }}>
602
- {opt.icon}
603
- </span>
604
- )}
605
- <span
606
- style={{
607
- overflow: 'hidden',
608
- textOverflow: 'ellipsis',
609
- whiteSpace: 'nowrap',
610
- }}
611
- >
612
- {sanitizeString(opt.label)}
613
- </span>
614
- </span>
615
- {opt.description && (
616
- <span
617
- style={{
618
- fontSize: '12px',
619
- color: theme.textMuted,
620
- marginTop: 1,
621
- overflow: 'hidden',
622
- textOverflow: 'ellipsis',
623
- whiteSpace: 'nowrap',
624
- }}
625
- >
626
- {sanitizeString(opt.description)}
627
- </span>
628
- )}
629
- </span>
630
- );
631
-
632
- return (
633
- <div
634
- key={opt.value}
635
- id={`${id}-opt-${opt.value}`}
636
- data-idx={flatIdx >= 0 ? flatIdx : undefined}
637
- role="option"
638
- aria-selected={isSelected}
639
- aria-disabled={opt.disabled || undefined}
640
- onClick={() => !opt.disabled && commitValue(opt.value)}
641
- onMouseEnter={() =>
642
- !opt.disabled && flatIdx >= 0 && setActiveIndex(flatIdx)
643
- }
644
- style={{
645
- height: optionHeight,
646
- boxSizing: 'border-box',
647
- padding: `0 ${sz.px}`,
648
- fontSize: sz.fontSize,
649
- fontFamily: 'inherit',
650
- color: opt.disabled ? theme.textMuted : theme.text,
651
- backgroundColor: isActive
652
- ? `${theme.primary}22`
653
- : isSelected
654
- ? `${theme.primary}12`
655
- : 'transparent',
656
- cursor: opt.disabled ? 'not-allowed' : 'pointer',
657
- display: 'flex',
658
- alignItems: 'center',
659
- justifyContent: 'space-between',
660
- gap: 8,
661
- transition: 'background-color 80ms',
662
- opacity: opt.disabled ? 0.5 : 1,
663
- userSelect: 'none',
664
- touchAction: 'manipulation',
665
- }}
666
- >
667
- {optionContent}
668
- {isSelected && !renderOption && (
669
- <svg
670
- width="14"
671
- height="14"
672
- viewBox="0 0 24 24"
673
- fill="none"
674
- stroke={theme.primary}
675
- strokeWidth="2.5"
676
- aria-hidden="true"
677
- style={{ flexShrink: 0 }}
678
- >
679
- <path d="M20 6L9 17l-5-5" />
680
- </svg>
681
- )}
682
- </div>
683
- );
684
- })}
685
- </div>
686
- {filteredOptions.length === 0 && (
687
- <div
688
- style={{
689
- padding: `${sz.py} ${sz.px}`,
690
- fontSize: sz.fontSize,
691
- fontFamily: 'inherit',
692
- color: theme.textMuted,
693
- textAlign: 'center',
694
- position: 'absolute',
695
- top: 0,
696
- left: 0,
697
- right: 0,
698
- }}
699
- >
700
- {isLoading ? 'Loading\u2026' : 'No options found'}
701
- </div>
702
- )}
703
- </div>
704
- ) : (
705
- /* Non-virtual: grouped rendering */
706
- <>
707
- {Object.entries(groups).map(([group, groupOpts]) => (
708
- <div key={group}>
709
- {group && (
710
- <div
711
- aria-hidden="true"
712
- style={{
713
- padding: '8px 12px 4px',
714
- fontSize: '11px',
715
- fontWeight: 700,
716
- letterSpacing: '0.08em',
717
- textTransform: 'uppercase',
718
- color: theme.textMuted,
719
- fontFamily: 'inherit',
720
- position: 'sticky',
721
- top: 0,
722
- backgroundColor: theme.surface,
723
- zIndex: 1,
724
- borderBottom: `1px solid ${theme.border}`,
725
- }}
726
- >
727
- {sanitizeString(group)}
728
- </div>
729
- )}
730
- {groupOpts.map((opt) => {
731
- const flatIdx = flatEnabled.indexOf(opt);
732
- const isActive = flatIdx === activeIndex;
733
- const isSelected = selectedValues.includes(opt.value);
734
-
735
- const optionContent = renderOption ? (
736
- renderOption(opt, isSelected)
737
- ) : (
738
- <span
739
- style={{
740
- display: 'flex',
741
- flexDirection: 'column',
742
- flex: 1,
743
- minWidth: 0,
744
- }}
745
- >
746
- <span
747
- style={{
748
- display: 'flex',
749
- alignItems: 'center',
750
- gap: 8,
751
- }}
752
- >
753
- {opt.icon && (
754
- <span style={{ flexShrink: 0, display: 'flex' }}>
755
- {opt.icon}
756
- </span>
757
- )}
758
- <span
759
- style={{
760
- overflow: 'hidden',
761
- textOverflow: 'ellipsis',
762
- whiteSpace: 'nowrap',
763
- }}
764
- >
765
- {sanitizeString(opt.label)}
766
- </span>
767
- </span>
768
- {opt.description && (
769
- <span
770
- style={{
771
- fontSize: '12px',
772
- color: theme.textMuted,
773
- marginTop: 1,
774
- overflow: 'hidden',
775
- textOverflow: 'ellipsis',
776
- whiteSpace: 'nowrap',
777
- }}
778
- >
779
- {sanitizeString(opt.description)}
780
- </span>
781
- )}
782
- </span>
783
- );
784
-
785
- return (
786
- <div
787
- key={opt.value}
788
- id={`${id}-opt-${opt.value}`}
789
- data-idx={flatIdx >= 0 ? flatIdx : undefined}
790
- role="option"
791
- aria-selected={isSelected}
792
- aria-disabled={opt.disabled || undefined}
793
- onClick={() => !opt.disabled && commitValue(opt.value)}
794
- onMouseEnter={() =>
795
- !opt.disabled && flatIdx >= 0 && setActiveIndex(flatIdx)
796
- }
797
- style={{
798
- padding: `${sz.py} ${sz.px}`,
799
- fontSize: sz.fontSize,
800
- fontFamily: 'inherit',
801
- color: opt.disabled ? theme.textMuted : theme.text,
802
- backgroundColor: isActive
803
- ? `${theme.primary}22`
804
- : isSelected
805
- ? `${theme.primary}12`
806
- : 'transparent',
807
- cursor: opt.disabled ? 'not-allowed' : 'pointer',
808
- display: 'flex',
809
- alignItems: 'center',
810
- justifyContent: 'space-between',
811
- gap: 8,
812
- transition: 'background-color 80ms',
813
- opacity: opt.disabled ? 0.5 : 1,
814
- userSelect: 'none',
815
- touchAction: 'manipulation',
816
- }}
817
- >
818
- {optionContent}
819
- {isSelected && !renderOption && (
820
- <svg
821
- width="14"
822
- height="14"
823
- viewBox="0 0 24 24"
824
- fill="none"
825
- stroke={theme.primary}
826
- strokeWidth="2.5"
827
- aria-hidden="true"
828
- style={{ flexShrink: 0 }}
829
- >
830
- <path d="M20 6L9 17l-5-5" />
831
- </svg>
832
- )}
833
- </div>
834
- );
835
- })}
836
- </div>
837
- ))}
838
-
839
- {filteredOptions.length === 0 && (
840
- <div
841
- style={{
842
- padding: `${sz.py} ${sz.px}`,
843
- fontSize: sz.fontSize,
844
- fontFamily: 'inherit',
845
- color: theme.textMuted,
846
- textAlign: 'center',
847
- }}
848
- >
849
- {isLoading ? 'Loading…' : 'No options found'}
850
- </div>
851
- )}
852
- </>
853
- )}
854
- </div>
855
- </div>,
856
- document.body,
857
- )
858
- : null;
859
-
860
- // ── Render ─────────────────────────────────────────────────────────────────
861
-
862
- const hasClearable =
863
- clearable && selectedValues.length > 0 && !isDisabled && !isLoading;
864
-
865
- return (
866
- <div
867
- className={cx(tkx('flex flex-col gap-1 w-full'), className)}
868
- style={style}
869
- >
870
- {label && (
871
- <label
872
- htmlFor={id}
873
- style={{
874
- fontSize: '14px',
875
- fontWeight: 500,
876
- fontFamily: 'inherit',
877
- color: theme.text,
878
- userSelect: 'none',
879
- }}
880
- >
881
- {sanitizeString(label)}
882
- </label>
883
- )}
884
-
885
- <div style={{ position: 'relative', width: '100%', opacity: isDisabled ? 0.55 : 1 }}>
886
- <button
887
- ref={triggerRef}
888
- id={id}
889
- type="button"
890
- role="combobox"
891
- aria-haspopup="listbox"
892
- aria-expanded={isOpen}
893
- aria-controls={listboxId}
894
- aria-activedescendant={activeOptionId}
895
- aria-invalid={hasError || undefined}
896
- aria-describedby={describedBy}
897
- aria-multiselectable={multiple}
898
- disabled={isDisabled}
899
- onClick={() => (isOpen ? setIsOpen(false) : openDropdown())}
900
- onKeyDown={handleTriggerKeyDown}
901
- style={{
902
- width: '100%',
903
- display: 'flex',
904
- alignItems: 'center',
905
- justifyContent: 'space-between',
906
- gap: 8,
907
- padding: multiple && selectedValues.length > 0
908
- ? `4px ${sz.px}`
909
- : `${sz.py} ${sz.px}`,
910
- fontSize: sz.fontSize,
911
- fontFamily: 'inherit',
912
- backgroundColor: theme.surface,
913
- color: selectedValues.length > 0 ? theme.text : theme.textMuted,
914
- border: `1.5px solid ${borderColor}`,
915
- borderRadius: 8,
916
- boxSizing: 'border-box',
917
- transition: 'border-color 150ms',
918
- textAlign: 'left',
919
- cursor: isDisabled ? 'not-allowed' : 'pointer',
920
- outline: 'none',
921
- minHeight: size === 'sm' ? 34 : size === 'lg' ? 50 : 42,
922
- flexWrap: 'wrap',
923
- touchAction: 'manipulation',
924
- }}
925
- >
926
- {/* Multi-select tags or single label */}
927
- <span
928
- style={{
929
- display: 'flex',
930
- alignItems: 'center',
931
- flexWrap: 'wrap',
932
- gap: 4,
933
- flex: 1,
934
- minWidth: 0,
935
- }}
936
- >
937
- {multiple && selectedOptionObjects.length > 0
938
- ? selectedOptionObjects.map((opt) => (
939
- <span
940
- key={opt.value}
941
- style={{
942
- display: 'inline-flex',
943
- alignItems: 'center',
944
- gap: 4,
945
- padding: `${sz.tagPy} ${sz.tagPx}`,
946
- fontSize: `calc(${sz.fontSize} - 1px)`,
947
- fontFamily: 'inherit',
948
- backgroundColor: `${theme.primary}22`,
949
- color: theme.primary,
950
- borderRadius: 6,
951
- border: `1px solid ${theme.primary}44`,
952
- lineHeight: 1.4,
953
- maxWidth: 150,
954
- overflow: 'hidden',
955
- textOverflow: 'ellipsis',
956
- whiteSpace: 'nowrap',
957
- }}
958
- >
959
- <span
960
- style={{
961
- overflow: 'hidden',
962
- textOverflow: 'ellipsis',
963
- whiteSpace: 'nowrap',
964
- maxWidth: 110,
965
- }}
966
- >
967
- {sanitizeString(opt.label)}
968
- </span>
969
- <span
970
- role="button"
971
- aria-label={`Remove ${sanitizeString(opt.label)}`}
972
- tabIndex={-1}
973
- onClick={(e) => removeTag(opt.value, e)}
974
- style={{
975
- cursor: 'pointer',
976
- flexShrink: 0,
977
- display: 'flex',
978
- alignItems: 'center',
979
- opacity: 0.8,
980
- }}
981
- >
982
- <svg
983
- width="10"
984
- height="10"
985
- viewBox="0 0 24 24"
986
- fill="none"
987
- stroke="currentColor"
988
- strokeWidth="2.5"
989
- aria-hidden="true"
990
- >
991
- <path d="M18 6L6 18M6 6l12 12" />
992
- </svg>
993
- </span>
994
- </span>
995
- ))
996
- : !multiple && selectedValues.length > 0
997
- ? (() => {
998
- const sel = options.find((o) => o.value === selectedValues[0]);
999
- return (
1000
- <span
1001
- style={{
1002
- overflow: 'hidden',
1003
- textOverflow: 'ellipsis',
1004
- whiteSpace: 'nowrap',
1005
- display: 'flex',
1006
- alignItems: 'center',
1007
- gap: 6,
1008
- }}
1009
- >
1010
- {sel?.icon && (
1011
- <span style={{ flexShrink: 0, display: 'flex' }}>
1012
- {sel.icon}
1013
- </span>
1014
- )}
1015
- {sel ? sanitizeString(sel.label) : ''}
1016
- </span>
1017
- );
1018
- })()
1019
- : (
1020
- <span style={{ opacity: 0.6 }}>
1021
- {sanitizeString(placeholder)}
1022
- </span>
1023
- )}
1024
- </span>
1025
-
1026
- {/* Right icons: clear + loading + chevron */}
1027
- <span
1028
- style={{
1029
- display: 'flex',
1030
- alignItems: 'center',
1031
- gap: 4,
1032
- flexShrink: 0,
1033
- color: theme.textMuted,
1034
- }}
1035
- >
1036
- {isLoading && <Spinner size={sz.iconSize} color={theme.primary} />}
1037
- {hasClearable && !isLoading && (
1038
- <span
1039
- role="button"
1040
- aria-label="Clear selection"
1041
- tabIndex={-1}
1042
- onClick={clearAll}
1043
- style={{
1044
- cursor: 'pointer',
1045
- display: 'flex',
1046
- alignItems: 'center',
1047
- lineHeight: 1,
1048
- opacity: 0.7,
1049
- transition: 'opacity 120ms',
1050
- }}
1051
- onMouseEnter={(e) =>
1052
- ((e.currentTarget as HTMLElement).style.opacity = '1')
1053
- }
1054
- onMouseLeave={(e) =>
1055
- ((e.currentTarget as HTMLElement).style.opacity = '0.7')
1056
- }
1057
- >
1058
- <svg
1059
- width={sz.iconSize}
1060
- height={sz.iconSize}
1061
- viewBox="0 0 24 24"
1062
- fill="none"
1063
- stroke="currentColor"
1064
- strokeWidth="2"
1065
- aria-hidden="true"
1066
- >
1067
- <path d="M18 6L6 18M6 6l12 12" />
1068
- </svg>
1069
- </span>
1070
- )}
1071
- <svg
1072
- width={sz.iconSize}
1073
- height={sz.iconSize}
1074
- viewBox="0 0 24 24"
1075
- fill="none"
1076
- stroke="currentColor"
1077
- strokeWidth="2"
1078
- aria-hidden="true"
1079
- style={{
1080
- transform: isOpen ? 'rotate(180deg)' : 'rotate(0deg)',
1081
- transition: 'transform 150ms',
1082
- flexShrink: 0,
1083
- }}
1084
- >
1085
- <path d="M6 9l6 6 6-6" />
1086
- </svg>
1087
- </span>
1088
- </button>
1089
- </div>
1090
-
1091
- {hint && !hasError && (
1092
- <span
1093
- id={hintId}
1094
- style={{ fontSize: '12px', color: theme.textMuted, fontFamily: 'inherit' }}
1095
- >
1096
- {sanitizeString(hint)}
1097
- </span>
1098
- )}
1099
- {hasError && errorMessage && (
1100
- <span
1101
- id={errorId}
1102
- role="alert"
1103
- style={{
1104
- fontSize: '12px',
1105
- color: theme.danger,
1106
- display: 'flex',
1107
- alignItems: 'center',
1108
- gap: 4,
1109
- fontFamily: 'inherit',
1110
- }}
1111
- >
1112
- <svg
1113
- width="12"
1114
- height="12"
1115
- viewBox="0 0 24 24"
1116
- fill="currentColor"
1117
- aria-hidden="true"
1118
- >
1119
- <path d="M12 2C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z" />
1120
- </svg>
1121
- {sanitizeString(errorMessage)}
1122
- </span>
1123
- )}
1124
-
1125
- {dropdownEl}
1126
- </div>
1127
- );
1128
- }
1129
-
1130
- TkxSelect.displayName = 'TkxSelect';