@health-samurai/react-components 0.0.0-alpha.4 → 0.0.0-alpha.6

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 (304) hide show
  1. package/dist/bundle.css +1375 -484
  2. package/dist/src/components/code-editor/http/grammar/http.d.ts +3 -0
  3. package/dist/src/components/code-editor/http/grammar/http.d.ts.map +1 -0
  4. package/dist/src/components/code-editor/http/grammar/http.grammar +74 -0
  5. package/dist/src/components/code-editor/http/grammar/http.js +38 -0
  6. package/dist/src/components/code-editor/http/grammar/http.js.map +1 -0
  7. package/dist/src/components/code-editor/http/grammar/http.terms.d.ts +2 -0
  8. package/dist/src/components/code-editor/http/grammar/http.terms.d.ts.map +1 -0
  9. package/dist/src/components/code-editor/http/grammar/http.terms.js +4 -0
  10. package/dist/src/components/code-editor/http/grammar/http.terms.js.map +1 -0
  11. package/dist/src/components/code-editor/http/grammar/http.test.d.ts +2 -0
  12. package/dist/src/components/code-editor/http/grammar/http.test.d.ts.map +1 -0
  13. package/dist/src/components/code-editor/http/grammar/http.test.js +80 -0
  14. package/dist/src/components/code-editor/http/grammar/http.test.js.map +1 -0
  15. package/dist/src/components/code-editor/http/index.d.ts +4 -0
  16. package/dist/src/components/code-editor/http/index.d.ts.map +1 -0
  17. package/dist/src/components/code-editor/http/index.js +66 -0
  18. package/dist/src/components/code-editor/http/index.js.map +1 -0
  19. package/dist/src/components/code-editor/index.d.ts +14 -2
  20. package/dist/src/components/code-editor/index.d.ts.map +1 -1
  21. package/dist/src/components/code-editor/index.js +309 -20
  22. package/dist/src/components/code-editor/index.js.map +1 -1
  23. package/dist/src/components/code-editor.stories.d.ts +1 -0
  24. package/dist/src/components/code-editor.stories.d.ts.map +1 -1
  25. package/dist/src/components/code-editor.stories.js +255 -2
  26. package/dist/src/components/code-editor.stories.js.map +1 -1
  27. package/dist/src/components/copy-icon.d.ts +5 -1
  28. package/dist/src/components/copy-icon.d.ts.map +1 -1
  29. package/dist/src/components/copy-icon.js +41 -3
  30. package/dist/src/components/copy-icon.js.map +1 -1
  31. package/dist/src/components/data-table.d.ts +8 -0
  32. package/dist/src/components/data-table.d.ts.map +1 -0
  33. package/dist/src/components/data-table.js +65 -0
  34. package/dist/src/components/data-table.js.map +1 -0
  35. package/dist/src/components/data-table.stories.d.ts +7 -0
  36. package/dist/src/components/data-table.stories.d.ts.map +1 -0
  37. package/dist/src/components/data-table.stories.js +44 -0
  38. package/dist/src/components/data-table.stories.js.map +1 -0
  39. package/dist/src/components/fhir-structure-view.d.ts +34 -0
  40. package/dist/src/components/fhir-structure-view.d.ts.map +1 -0
  41. package/dist/src/components/fhir-structure-view.js +229 -0
  42. package/dist/src/components/fhir-structure-view.js.map +1 -0
  43. package/dist/src/components/fhir-structure-view.stories.d.ts +7 -0
  44. package/dist/src/components/fhir-structure-view.stories.d.ts.map +1 -0
  45. package/dist/src/components/fhir-structure-view.stories.js +447 -0
  46. package/dist/src/components/fhir-structure-view.stories.js.map +1 -0
  47. package/dist/src/components/patient-table.d.ts +73 -0
  48. package/dist/src/components/patient-table.d.ts.map +1 -0
  49. package/dist/src/components/patient-table.js +921 -0
  50. package/dist/src/components/patient-table.js.map +1 -0
  51. package/dist/src/components/patient-table.stories.d.ts +111 -0
  52. package/dist/src/components/patient-table.stories.d.ts.map +1 -0
  53. package/dist/src/components/patient-table.stories.js +172 -0
  54. package/dist/src/components/patient-table.stories.js.map +1 -0
  55. package/dist/src/components/request-line-editor.d.ts +13 -35
  56. package/dist/src/components/request-line-editor.d.ts.map +1 -1
  57. package/dist/src/components/request-line-editor.js +72 -49
  58. package/dist/src/components/request-line-editor.js.map +1 -1
  59. package/dist/src/components/request-line-editor.stories.d.ts.map +1 -1
  60. package/dist/src/components/request-line-editor.stories.js +17 -53
  61. package/dist/src/components/request-line-editor.stories.js.map +1 -1
  62. package/dist/src/components/segment-control.d.ts +16 -0
  63. package/dist/src/components/segment-control.d.ts.map +1 -0
  64. package/dist/src/components/segment-control.js +48 -0
  65. package/dist/src/components/segment-control.js.map +1 -0
  66. package/dist/src/components/segment-control.stories.d.ts +15 -0
  67. package/dist/src/components/segment-control.stories.d.ts.map +1 -0
  68. package/dist/src/components/segment-control.stories.js +33 -0
  69. package/dist/src/components/segment-control.stories.js.map +1 -0
  70. package/dist/src/components/split-button.d.ts +5 -0
  71. package/dist/src/components/split-button.d.ts.map +1 -0
  72. package/dist/src/components/split-button.js +12 -0
  73. package/dist/src/components/split-button.js.map +1 -0
  74. package/dist/src/components/split-button.stories.d.ts +7 -0
  75. package/dist/src/components/split-button.stories.d.ts.map +1 -0
  76. package/dist/src/components/split-button.stories.js +57 -0
  77. package/dist/src/components/split-button.stories.js.map +1 -0
  78. package/dist/src/components/tree-view.d.ts +22 -0
  79. package/dist/src/components/tree-view.d.ts.map +1 -0
  80. package/dist/src/components/tree-view.js +101 -0
  81. package/dist/src/components/tree-view.js.map +1 -0
  82. package/dist/src/components/tree-view.stories.d.ts +13 -0
  83. package/dist/src/components/tree-view.stories.d.ts.map +1 -0
  84. package/dist/src/components/tree-view.stories.js +274 -0
  85. package/dist/src/components/tree-view.stories.js.map +1 -0
  86. package/dist/src/icons.d.ts +9 -0
  87. package/dist/src/icons.d.ts.map +1 -0
  88. package/dist/src/icons.js +279 -0
  89. package/dist/src/icons.js.map +1 -0
  90. package/dist/src/index.css +42 -3
  91. package/dist/src/index.d.ts +9 -1
  92. package/dist/src/index.d.ts.map +1 -1
  93. package/dist/src/index.js +9 -1
  94. package/dist/src/index.js.map +1 -1
  95. package/dist/src/shadcn/components/ui/accordion.d.ts.map +1 -1
  96. package/dist/src/shadcn/components/ui/accordion.js +23 -5
  97. package/dist/src/shadcn/components/ui/accordion.js.map +1 -1
  98. package/dist/src/shadcn/components/ui/alert-dialog.d.ts +3 -1
  99. package/dist/src/shadcn/components/ui/alert-dialog.d.ts.map +1 -1
  100. package/dist/src/shadcn/components/ui/alert-dialog.js +5 -2
  101. package/dist/src/shadcn/components/ui/alert-dialog.js.map +1 -1
  102. package/dist/src/shadcn/components/ui/alert.d.ts.map +1 -1
  103. package/dist/src/shadcn/components/ui/alert.js +12 -5
  104. package/dist/src/shadcn/components/ui/alert.js.map +1 -1
  105. package/dist/src/shadcn/components/ui/avatar.d.ts.map +1 -1
  106. package/dist/src/shadcn/components/ui/avatar.js +4 -3
  107. package/dist/src/shadcn/components/ui/avatar.js.map +1 -1
  108. package/dist/src/shadcn/components/ui/badge.d.ts.map +1 -1
  109. package/dist/src/shadcn/components/ui/badge.js +16 -5
  110. package/dist/src/shadcn/components/ui/badge.js.map +1 -1
  111. package/dist/src/shadcn/components/ui/breadcrumb.d.ts.map +1 -1
  112. package/dist/src/shadcn/components/ui/breadcrumb.js +6 -6
  113. package/dist/src/shadcn/components/ui/breadcrumb.js.map +1 -1
  114. package/dist/src/shadcn/components/ui/button.d.ts.map +1 -1
  115. package/dist/src/shadcn/components/ui/button.js +19 -11
  116. package/dist/src/shadcn/components/ui/button.js.map +1 -1
  117. package/dist/src/shadcn/components/ui/card.d.ts.map +1 -1
  118. package/dist/src/shadcn/components/ui/card.js +14 -6
  119. package/dist/src/shadcn/components/ui/card.js.map +1 -1
  120. package/dist/src/shadcn/components/ui/checkbox.d.ts.map +1 -1
  121. package/dist/src/shadcn/components/ui/checkbox.js +20 -5
  122. package/dist/src/shadcn/components/ui/checkbox.js.map +1 -1
  123. package/dist/src/shadcn/components/ui/checkbox.stories.d.ts.map +1 -1
  124. package/dist/src/shadcn/components/ui/checkbox.stories.js +44 -35
  125. package/dist/src/shadcn/components/ui/checkbox.stories.js.map +1 -1
  126. package/dist/src/shadcn/components/ui/combobox.d.ts +18 -0
  127. package/dist/src/shadcn/components/ui/combobox.d.ts.map +1 -0
  128. package/dist/src/shadcn/components/ui/combobox.js +121 -0
  129. package/dist/src/shadcn/components/ui/combobox.js.map +1 -0
  130. package/dist/src/shadcn/components/ui/combobox.stories.d.ts +11 -0
  131. package/dist/src/shadcn/components/ui/combobox.stories.d.ts.map +1 -0
  132. package/dist/src/shadcn/components/ui/combobox.stories.js +16 -0
  133. package/dist/src/shadcn/components/ui/combobox.stories.js.map +1 -0
  134. package/dist/src/shadcn/components/ui/command.d.ts.map +1 -1
  135. package/dist/src/shadcn/components/ui/command.js +73 -12
  136. package/dist/src/shadcn/components/ui/command.js.map +1 -1
  137. package/dist/src/shadcn/components/ui/command.stories.js +0 -1
  138. package/dist/src/shadcn/components/ui/command.stories.js.map +1 -1
  139. package/dist/src/shadcn/components/ui/dialog.d.ts.map +1 -1
  140. package/dist/src/shadcn/components/ui/dialog.js +35 -7
  141. package/dist/src/shadcn/components/ui/dialog.js.map +1 -1
  142. package/dist/src/shadcn/components/ui/drawer.d.ts.map +1 -1
  143. package/dist/src/shadcn/components/ui/drawer.js +26 -5
  144. package/dist/src/shadcn/components/ui/drawer.js.map +1 -1
  145. package/dist/src/shadcn/components/ui/dropdown-menu.d.ts.map +1 -1
  146. package/dist/src/shadcn/components/ui/dropdown-menu.js +12 -1
  147. package/dist/src/shadcn/components/ui/dropdown-menu.js.map +1 -1
  148. package/dist/src/shadcn/components/ui/form.d.ts.map +1 -1
  149. package/dist/src/shadcn/components/ui/form.js +12 -4
  150. package/dist/src/shadcn/components/ui/form.js.map +1 -1
  151. package/dist/src/shadcn/components/ui/input.d.ts +3 -1
  152. package/dist/src/shadcn/components/ui/input.d.ts.map +1 -1
  153. package/dist/src/shadcn/components/ui/input.js +126 -17
  154. package/dist/src/shadcn/components/ui/input.js.map +1 -1
  155. package/dist/src/shadcn/components/ui/label.d.ts.map +1 -1
  156. package/dist/src/shadcn/components/ui/label.js +8 -1
  157. package/dist/src/shadcn/components/ui/label.js.map +1 -1
  158. package/dist/src/shadcn/components/ui/menubar.d.ts.map +1 -1
  159. package/dist/src/shadcn/components/ui/menubar.js +35 -13
  160. package/dist/src/shadcn/components/ui/menubar.js.map +1 -1
  161. package/dist/src/shadcn/components/ui/pagination.d.ts.map +1 -1
  162. package/dist/src/shadcn/components/ui/pagination.js +6 -6
  163. package/dist/src/shadcn/components/ui/pagination.js.map +1 -1
  164. package/dist/src/shadcn/components/ui/popover.d.ts.map +1 -1
  165. package/dist/src/shadcn/components/ui/popover.js +12 -1
  166. package/dist/src/shadcn/components/ui/popover.js.map +1 -1
  167. package/dist/src/shadcn/components/ui/progress.d.ts.map +1 -1
  168. package/dist/src/shadcn/components/ui/progress.js +6 -2
  169. package/dist/src/shadcn/components/ui/progress.js.map +1 -1
  170. package/dist/src/shadcn/components/ui/radio-group.d.ts.map +1 -1
  171. package/dist/src/shadcn/components/ui/radio-group.js +11 -6
  172. package/dist/src/shadcn/components/ui/radio-group.js.map +1 -1
  173. package/dist/src/shadcn/components/ui/radio-group.stories.d.ts.map +1 -1
  174. package/dist/src/shadcn/components/ui/radio-group.stories.js +57 -34
  175. package/dist/src/shadcn/components/ui/radio-group.stories.js.map +1 -1
  176. package/dist/src/shadcn/components/ui/scroll-area.d.ts.map +1 -1
  177. package/dist/src/shadcn/components/ui/scroll-area.js +9 -3
  178. package/dist/src/shadcn/components/ui/scroll-area.js.map +1 -1
  179. package/dist/src/shadcn/components/ui/select.d.ts.map +1 -1
  180. package/dist/src/shadcn/components/ui/select.js +49 -14
  181. package/dist/src/shadcn/components/ui/select.js.map +1 -1
  182. package/dist/src/shadcn/components/ui/select.stories.d.ts.map +1 -1
  183. package/dist/src/shadcn/components/ui/select.stories.js +1 -4
  184. package/dist/src/shadcn/components/ui/select.stories.js.map +1 -1
  185. package/dist/src/shadcn/components/ui/separator.d.ts.map +1 -1
  186. package/dist/src/shadcn/components/ui/separator.js +7 -1
  187. package/dist/src/shadcn/components/ui/separator.js.map +1 -1
  188. package/dist/src/shadcn/components/ui/sidebar.d.ts.map +1 -1
  189. package/dist/src/shadcn/components/ui/sidebar.js +20 -6
  190. package/dist/src/shadcn/components/ui/sidebar.js.map +1 -1
  191. package/dist/src/shadcn/components/ui/skeleton.d.ts.map +1 -1
  192. package/dist/src/shadcn/components/ui/skeleton.js +3 -1
  193. package/dist/src/shadcn/components/ui/skeleton.js.map +1 -1
  194. package/dist/src/shadcn/components/ui/slider.d.ts.map +1 -1
  195. package/dist/src/shadcn/components/ui/slider.js +34 -4
  196. package/dist/src/shadcn/components/ui/slider.js.map +1 -1
  197. package/dist/src/shadcn/components/ui/sonner.d.ts +16 -1
  198. package/dist/src/shadcn/components/ui/sonner.d.ts.map +1 -1
  199. package/dist/src/shadcn/components/ui/sonner.js +23 -3
  200. package/dist/src/shadcn/components/ui/sonner.js.map +1 -1
  201. package/dist/src/shadcn/components/ui/sonner.stories.d.ts.map +1 -1
  202. package/dist/src/shadcn/components/ui/sonner.stories.js +19 -11
  203. package/dist/src/shadcn/components/ui/sonner.stories.js.map +1 -1
  204. package/dist/src/shadcn/components/ui/switch.d.ts.map +1 -1
  205. package/dist/src/shadcn/components/ui/switch.js +18 -2
  206. package/dist/src/shadcn/components/ui/switch.js.map +1 -1
  207. package/dist/src/shadcn/components/ui/table.d.ts.map +1 -1
  208. package/dist/src/shadcn/components/ui/table.js +12 -8
  209. package/dist/src/shadcn/components/ui/table.js.map +1 -1
  210. package/dist/src/shadcn/components/ui/tabs.d.ts +21 -3
  211. package/dist/src/shadcn/components/ui/tabs.d.ts.map +1 -1
  212. package/dist/src/shadcn/components/ui/tabs.js +315 -9
  213. package/dist/src/shadcn/components/ui/tabs.js.map +1 -1
  214. package/dist/src/shadcn/components/ui/tabs.stories.d.ts.map +1 -1
  215. package/dist/src/shadcn/components/ui/tabs.stories.js +50 -1
  216. package/dist/src/shadcn/components/ui/tabs.stories.js.map +1 -1
  217. package/dist/src/shadcn/components/ui/textarea.d.ts.map +1 -1
  218. package/dist/src/shadcn/components/ui/textarea.js +15 -1
  219. package/dist/src/shadcn/components/ui/textarea.js.map +1 -1
  220. package/dist/src/shadcn/components/ui/toggle-group.d.ts.map +1 -1
  221. package/dist/src/shadcn/components/ui/toggle-group.js +6 -2
  222. package/dist/src/shadcn/components/ui/toggle-group.js.map +1 -1
  223. package/dist/src/shadcn/components/ui/toggle.d.ts.map +1 -1
  224. package/dist/src/shadcn/components/ui/toggle.js +18 -6
  225. package/dist/src/shadcn/components/ui/toggle.js.map +1 -1
  226. package/dist/src/shadcn/components/ui/tooltip.d.ts.map +1 -1
  227. package/dist/src/shadcn/components/ui/tooltip.js +11 -1
  228. package/dist/src/shadcn/components/ui/tooltip.js.map +1 -1
  229. package/dist/src/shadcn/components/ui/tree.d.ts +28 -0
  230. package/dist/src/shadcn/components/ui/tree.d.ts.map +1 -0
  231. package/dist/src/shadcn/components/ui/tree.js +122 -0
  232. package/dist/src/shadcn/components/ui/tree.js.map +1 -0
  233. package/dist/src/typography.css +12 -0
  234. package/package.json +13 -2
  235. package/src/components/code-editor/http/grammar/http.grammar +74 -0
  236. package/src/components/code-editor/http/grammar/http.terms.ts +9 -0
  237. package/src/components/code-editor/http/grammar/http.test.ts +110 -0
  238. package/src/components/code-editor/http/grammar/http.ts +21 -0
  239. package/src/components/code-editor/http/index.ts +87 -0
  240. package/src/components/code-editor/index.tsx +307 -21
  241. package/src/components/code-editor.stories.tsx +295 -1
  242. package/src/components/copy-icon.tsx +57 -3
  243. package/src/components/data-table.stories.tsx +38 -0
  244. package/src/components/data-table.tsx +117 -0
  245. package/src/components/fhir-structure-view.stories.tsx +439 -0
  246. package/src/components/fhir-structure-view.tsx +231 -0
  247. package/src/components/patient-table.stories.tsx +111 -0
  248. package/src/components/patient-table.tsx +1301 -0
  249. package/src/components/request-line-editor.stories.tsx +17 -27
  250. package/src/components/request-line-editor.tsx +98 -61
  251. package/src/components/segment-control.stories.tsx +29 -0
  252. package/src/components/segment-control.tsx +80 -0
  253. package/src/components/split-button.stories.tsx +49 -0
  254. package/src/components/split-button.tsx +17 -0
  255. package/src/components/tree-view.stories.tsx +259 -0
  256. package/src/components/tree-view.tsx +172 -0
  257. package/src/icons.tsx +287 -0
  258. package/src/index.css +42 -3
  259. package/src/index.tsx +9 -2
  260. package/src/shadcn/components/ui/accordion.tsx +66 -8
  261. package/src/shadcn/components/ui/alert-dialog.tsx +6 -2
  262. package/src/shadcn/components/ui/alert.tsx +53 -15
  263. package/src/shadcn/components/ui/avatar.tsx +17 -6
  264. package/src/shadcn/components/ui/badge.tsx +67 -18
  265. package/src/shadcn/components/ui/breadcrumb.tsx +35 -7
  266. package/src/shadcn/components/ui/button.tsx +118 -57
  267. package/src/shadcn/components/ui/card.tsx +44 -13
  268. package/src/shadcn/components/ui/checkbox.stories.tsx +20 -24
  269. package/src/shadcn/components/ui/checkbox.tsx +45 -4
  270. package/src/shadcn/components/ui/combobox.stories.tsx +19 -0
  271. package/src/shadcn/components/ui/combobox.tsx +142 -0
  272. package/src/shadcn/components/ui/command.stories.tsx +1 -1
  273. package/src/shadcn/components/ui/command.tsx +192 -36
  274. package/src/shadcn/components/ui/dialog.tsx +101 -13
  275. package/src/shadcn/components/ui/drawer.tsx +93 -18
  276. package/src/shadcn/components/ui/dropdown-menu.tsx +37 -9
  277. package/src/shadcn/components/ui/form.tsx +16 -4
  278. package/src/shadcn/components/ui/input.tsx +400 -29
  279. package/src/shadcn/components/ui/label.tsx +21 -4
  280. package/src/shadcn/components/ui/menubar.tsx +188 -43
  281. package/src/shadcn/components/ui/pagination.tsx +12 -6
  282. package/src/shadcn/components/ui/popover.tsx +35 -4
  283. package/src/shadcn/components/ui/progress.tsx +21 -5
  284. package/src/shadcn/components/ui/radio-group.stories.tsx +22 -14
  285. package/src/shadcn/components/ui/radio-group.tsx +42 -5
  286. package/src/shadcn/components/ui/scroll-area.tsx +33 -5
  287. package/src/shadcn/components/ui/select.stories.tsx +0 -2
  288. package/src/shadcn/components/ui/select.tsx +184 -33
  289. package/src/shadcn/components/ui/separator.tsx +15 -5
  290. package/src/shadcn/components/ui/sidebar.tsx +68 -26
  291. package/src/shadcn/components/ui/skeleton.tsx +4 -1
  292. package/src/shadcn/components/ui/slider.tsx +82 -11
  293. package/src/shadcn/components/ui/sonner.stories.tsx +19 -15
  294. package/src/shadcn/components/ui/sonner.tsx +53 -3
  295. package/src/shadcn/components/ui/switch.tsx +53 -7
  296. package/src/shadcn/components/ui/table.tsx +38 -11
  297. package/src/shadcn/components/ui/tabs.stories.tsx +32 -0
  298. package/src/shadcn/components/ui/tabs.tsx +456 -17
  299. package/src/shadcn/components/ui/textarea.tsx +42 -4
  300. package/src/shadcn/components/ui/toggle-group.tsx +27 -5
  301. package/src/shadcn/components/ui/toggle.tsx +59 -18
  302. package/src/shadcn/components/ui/tooltip.tsx +33 -8
  303. package/src/shadcn/components/ui/tree.tsx +233 -0
  304. package/src/typography.css +12 -0
@@ -0,0 +1,142 @@
1
+ "use client";
2
+
3
+ import { CheckIcon } from "lucide-react";
4
+ import * as React from "react";
5
+ import {
6
+ Command,
7
+ CommandEmpty,
8
+ CommandInput,
9
+ CommandItem,
10
+ CommandList,
11
+ } from "#shadcn/components/ui/command";
12
+ import {
13
+ Select,
14
+ SelectContent,
15
+ SelectTrigger,
16
+ SelectValue,
17
+ } from "#shadcn/components/ui/select";
18
+ import { cn } from "#shadcn/lib/utils";
19
+
20
+ export interface ComboboxOption {
21
+ value: string;
22
+ label: string;
23
+ }
24
+
25
+ interface ComboboxProps {
26
+ options: ComboboxOption[];
27
+ value?: string;
28
+ onValueChange?: (value: string) => void;
29
+ placeholder?: string;
30
+ searchPlaceholder?: string;
31
+ emptyText?: string;
32
+ disabled?: boolean;
33
+ className?: string;
34
+ }
35
+
36
+ export function Combobox({
37
+ options,
38
+ value,
39
+ onValueChange,
40
+ placeholder = "Select option...",
41
+ searchPlaceholder = "Search...",
42
+ emptyText = "No options found.",
43
+ disabled = false,
44
+ className,
45
+ }: ComboboxProps) {
46
+ const [open, setOpen] = React.useState(false);
47
+ const [searchValue, setSearchValue] = React.useState("");
48
+ const inputRef = React.useRef<HTMLInputElement>(null);
49
+
50
+ const filteredOptions = React.useMemo(() => {
51
+ if (!searchValue) return options;
52
+ return options.filter((option) =>
53
+ option.label.toLowerCase().includes(searchValue.toLowerCase()),
54
+ );
55
+ }, [options, searchValue]);
56
+
57
+ const selectedOption = options.find((option) => option.value === value);
58
+
59
+ // Reset search when closing and auto-focus when opening
60
+ React.useEffect(() => {
61
+ if (!open) {
62
+ setSearchValue("");
63
+ } else {
64
+ // Auto-focus on search input when opening
65
+ setTimeout(() => {
66
+ inputRef.current?.focus();
67
+ }, 0);
68
+ }
69
+ }, [open]);
70
+
71
+ return (
72
+ <Select
73
+ value={value || ""}
74
+ {...(onValueChange && { onValueChange })}
75
+ disabled={disabled}
76
+ open={open}
77
+ onOpenChange={setOpen}
78
+ >
79
+ <SelectTrigger className={className}>
80
+ <SelectValue placeholder={placeholder}>
81
+ {selectedOption?.label}
82
+ </SelectValue>
83
+ </SelectTrigger>
84
+ <SelectContent className="p-0 [&_[data-radix-select-viewport]]:p-0">
85
+ <Command className="w-full">
86
+ <CommandInput
87
+ ref={inputRef}
88
+ placeholder={searchPlaceholder}
89
+ value={searchValue}
90
+ onValueChange={setSearchValue}
91
+ />
92
+ <CommandList>
93
+ <CommandEmpty>{emptyText}</CommandEmpty>
94
+
95
+ {filteredOptions.map((option) => (
96
+ <CommandItem
97
+ key={option.value}
98
+ value={option.value}
99
+ data-state={value === option.value ? "checked" : undefined}
100
+ onSelect={(currentValue) => {
101
+ onValueChange?.(currentValue);
102
+ setOpen(false);
103
+ }}
104
+ >
105
+ {option.label}
106
+ <CheckIcon
107
+ className={cn(
108
+ "ml-auto size-4",
109
+ value === option.value ? "opacity-100" : "opacity-0",
110
+ )}
111
+ />
112
+ </CommandItem>
113
+ ))}
114
+ </CommandList>
115
+ </Command>
116
+ </SelectContent>
117
+ </Select>
118
+ );
119
+ }
120
+
121
+ // Demo component for Storybook
122
+ const demoOptions = [
123
+ { value: "next.js", label: "Next.js" },
124
+ { value: "sveltekit", label: "SvelteKit" },
125
+ { value: "nuxt.js", label: "Nuxt.js" },
126
+ { value: "remix", label: "Remix" },
127
+ { value: "astro", label: "Astro" },
128
+ ];
129
+
130
+ export function ComboboxDemo() {
131
+ const [value, setValue] = React.useState("");
132
+
133
+ return (
134
+ <Combobox
135
+ options={demoOptions}
136
+ value={value}
137
+ onValueChange={setValue}
138
+ placeholder="Select framework..."
139
+ searchPlaceholder="Search framework..."
140
+ />
141
+ );
142
+ }
@@ -27,7 +27,7 @@ type Story = StoryObj<typeof meta>;
27
27
 
28
28
  export const Demo = {
29
29
  render: () => (
30
- <Command className="rounded-lg border shadow-md md:min-w-[450px]">
30
+ <Command>
31
31
  <CommandInput placeholder="Type a command or search..." />
32
32
  <CommandList>
33
33
  <CommandEmpty>No results found.</CommandEmpty>
@@ -10,6 +10,186 @@ import {
10
10
  } from "#shadcn/components/ui/dialog";
11
11
  import { cn } from "#shadcn/lib/utils";
12
12
 
13
+ // Command Root
14
+ const commandStyles = cn(
15
+ // Layout
16
+ "flex",
17
+ "h-full",
18
+ "w-full",
19
+ "flex-col",
20
+ "overflow-hidden",
21
+ "rounded-md",
22
+ // Colors
23
+ "bg-bg-primary",
24
+ "text-text-primary",
25
+ );
26
+
27
+ // Command Dialog
28
+ const commandDialogContentStyles = cn(
29
+ // Layout
30
+ "overflow-hidden",
31
+ "p-0",
32
+ );
33
+
34
+ const commandDialogCommandStyles = cn(
35
+ // Group headings
36
+ "[&_[cmdk-group-heading]]:text-muted-foreground",
37
+ "[&_[cmdk-group-heading]]:px-2",
38
+ "[&_[cmdk-group-heading]]:font-medium",
39
+ // Groups
40
+ "[&_[cmdk-group]]:px-2",
41
+ "[&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0",
42
+ // Input wrapper
43
+ "[&_[cmdk-input-wrapper]]:h-12",
44
+ "**:data-[slot=command-input-wrapper]:h-12",
45
+ // Input wrapper SVG
46
+ "[&_[cmdk-input-wrapper]_svg]:h-5",
47
+ "[&_[cmdk-input-wrapper]_svg]:w-5",
48
+ // Input
49
+ "[&_[cmdk-input]]:h-12",
50
+ // Items
51
+ "[&_[cmdk-item]]:px-2",
52
+ "[&_[cmdk-item]]:py-3",
53
+ // Item SVG
54
+ "[&_[cmdk-item]_svg]:h-5",
55
+ "[&_[cmdk-item]_svg]:w-5",
56
+ );
57
+
58
+ // Command Input Wrapper
59
+ const commandInputWrapperStyles = cn(
60
+ // Layout
61
+ "flex",
62
+ "h-9",
63
+ "items-center",
64
+ "gap-2",
65
+ "px-3",
66
+ // Border
67
+ "border-b",
68
+ "border-border-separator",
69
+ // Animation
70
+ "transition-colors",
71
+ "duration-300",
72
+ );
73
+
74
+ // Command Input Icon
75
+ const commandInputIconStyles = cn(
76
+ // Size
77
+ "size-4",
78
+ "shrink-0",
79
+ // Colors
80
+ "text-text-tertiary",
81
+ );
82
+
83
+ // Command Input
84
+ const commandInputStyles = cn(
85
+ // Layout
86
+ "flex",
87
+ "h-10",
88
+ "w-full",
89
+ "rounded-md",
90
+ "py-3",
91
+ // Background
92
+ "bg-transparent",
93
+ // Typography
94
+ "typo-body",
95
+ // Colors
96
+ "text-text-primary",
97
+ "placeholder:text-text-quternary",
98
+ "file:text-text-primary",
99
+ // States
100
+ "outline-hidden",
101
+ "disabled:cursor-not-allowed",
102
+ "disabled:opacity-50",
103
+ );
104
+
105
+ // Command List
106
+ const commandListStyles = cn(
107
+ // Layout
108
+ "max-h-[300px]",
109
+ "scroll-py-1",
110
+ // Overflow
111
+ "overflow-x-hidden",
112
+ "overflow-y-auto",
113
+ "p-2",
114
+ );
115
+
116
+ // Command Empty
117
+ const commandEmptyStyles = cn(
118
+ // Layout
119
+ "py-6",
120
+ "text-center",
121
+ // Typography
122
+ "typo-body",
123
+ // Colors
124
+ "text-text-tertiary",
125
+ );
126
+
127
+ // Command Group
128
+ const commandGroupStyles = cn(
129
+ // Layout
130
+ "overflow-hidden",
131
+ "p-1",
132
+ "group",
133
+ // Colors
134
+ "text-text-tertiary",
135
+ // Group heading styles
136
+ "[&_[cmdk-group-heading]]:text-text-quaternary",
137
+ "[&_[cmdk-group-heading]]:px-2",
138
+ "[&_[cmdk-group-heading]]:py-1.5",
139
+ "[&_[cmdk-group-heading]]:text-xs",
140
+ );
141
+
142
+ // Command Separator
143
+ const commandSeparatorStyles = cn(
144
+ // Layout
145
+ "-mx-1",
146
+ "h-px",
147
+ // Colors
148
+ "bg-border-separator",
149
+ );
150
+
151
+ // Command Item
152
+ const commandItemStyles = cn(
153
+ // Layout
154
+ "relative",
155
+ "flex",
156
+ "cursor-default",
157
+ "items-center",
158
+ "gap-2",
159
+ "rounded-md",
160
+ "px-2",
161
+ "py-1.5",
162
+ "select-none",
163
+ // Typography
164
+ "typo-body",
165
+ // Colors
166
+ "text-text-primary",
167
+ // States
168
+ "outline-hidden",
169
+ "data-[state=checked]:bg-bg-tertiary",
170
+ "group-hover:data-[state=checked]:bg-transparent",
171
+ "hover:bg-bg-tertiary",
172
+ "data-[state=checked]:text-text-primary",
173
+ "data-[disabled=true]:pointer-events-none",
174
+ "data-[disabled=true]:opacity-50",
175
+ // SVG styles
176
+ "[&_svg:not([class*='text-'])]:text-text-quaternary",
177
+ "[&_svg]:pointer-events-none",
178
+ "[&_svg]:shrink-0",
179
+ "[&_svg:not([class*='size-'])]:size-4",
180
+ );
181
+
182
+ // Command Shortcut
183
+ const commandShortcutStyles = cn(
184
+ // Layout
185
+ "ml-auto",
186
+ // Typography
187
+ "typo-body",
188
+ "tracking-widest",
189
+ // Colors
190
+ "text-text-quaternary",
191
+ );
192
+
13
193
  function Command({
14
194
  className,
15
195
  ...props
@@ -17,10 +197,7 @@ function Command({
17
197
  return (
18
198
  <CommandPrimitive
19
199
  data-slot="command"
20
- className={cn(
21
- "bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md",
22
- className,
23
- )}
200
+ className={cn(commandStyles, className)}
24
201
  {...props}
25
202
  />
26
203
  );
@@ -46,12 +223,10 @@ function CommandDialog({
46
223
  <DialogDescription>{description}</DialogDescription>
47
224
  </DialogHeader>
48
225
  <DialogContent
49
- className={cn("overflow-hidden p-0", className)}
226
+ className={cn(commandDialogContentStyles, className)}
50
227
  showCloseButton={showCloseButton}
51
228
  >
52
- <Command className="[&_[cmdk-group-heading]]:text-muted-foreground **:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
53
- {children}
54
- </Command>
229
+ <Command className={commandDialogCommandStyles}>{children}</Command>
55
230
  </DialogContent>
56
231
  </Dialog>
57
232
  );
@@ -64,15 +239,12 @@ function CommandInput({
64
239
  return (
65
240
  <div
66
241
  data-slot="command-input-wrapper"
67
- className="flex h-9 items-center gap-2 border-b px-3"
242
+ className={commandInputWrapperStyles}
68
243
  >
69
- <SearchIcon className="size-4 shrink-0 opacity-50" />
244
+ <SearchIcon className={commandInputIconStyles} />
70
245
  <CommandPrimitive.Input
71
246
  data-slot="command-input"
72
- className={cn(
73
- "placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50",
74
- className,
75
- )}
247
+ className={cn(commandInputStyles, className)}
76
248
  {...props}
77
249
  />
78
250
  </div>
@@ -86,10 +258,7 @@ function CommandList({
86
258
  return (
87
259
  <CommandPrimitive.List
88
260
  data-slot="command-list"
89
- className={cn(
90
- "max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto",
91
- className,
92
- )}
261
+ className={cn(commandListStyles, className)}
93
262
  {...props}
94
263
  />
95
264
  );
@@ -101,7 +270,7 @@ function CommandEmpty({
101
270
  return (
102
271
  <CommandPrimitive.Empty
103
272
  data-slot="command-empty"
104
- className="py-6 text-center text-sm"
273
+ className={commandEmptyStyles}
105
274
  {...props}
106
275
  />
107
276
  );
@@ -114,10 +283,7 @@ function CommandGroup({
114
283
  return (
115
284
  <CommandPrimitive.Group
116
285
  data-slot="command-group"
117
- className={cn(
118
- "text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium",
119
- className,
120
- )}
286
+ className={cn(commandGroupStyles, className)}
121
287
  {...props}
122
288
  />
123
289
  );
@@ -130,7 +296,7 @@ function CommandSeparator({
130
296
  return (
131
297
  <CommandPrimitive.Separator
132
298
  data-slot="command-separator"
133
- className={cn("bg-border -mx-1 h-px", className)}
299
+ className={cn(commandSeparatorStyles, className)}
134
300
  {...props}
135
301
  />
136
302
  );
@@ -143,14 +309,7 @@ function CommandItem({
143
309
  return (
144
310
  <CommandPrimitive.Item
145
311
  data-slot="command-item"
146
- className={cn(
147
- "data-[selected=true]:bg-(--color-surface-1) text-(--color-elements-assistive)",
148
- "data-[selected=true]:text-(--color-elements-readable) [&_svg:not([class*='text-'])]:text-muted-foreground",
149
- "relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none",
150
- "data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none",
151
- "[&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
152
- className,
153
- )}
312
+ className={cn(commandItemStyles, className)}
154
313
  {...props}
155
314
  />
156
315
  );
@@ -163,10 +322,7 @@ function CommandShortcut({
163
322
  return (
164
323
  <span
165
324
  data-slot="command-shortcut"
166
- className={cn(
167
- "text-muted-foreground ml-auto text-xs tracking-widest",
168
- className,
169
- )}
325
+ className={cn(commandShortcutStyles, className)}
170
326
  {...props}
171
327
  />
172
328
  );
@@ -4,6 +4,89 @@ import type * as React from "react";
4
4
 
5
5
  import { cn } from "#shadcn/lib/utils";
6
6
 
7
+ // Dialog overlay styles
8
+ const dialogOverlayStyles = cn(
9
+ // Layout
10
+ "fixed",
11
+ "inset-0",
12
+ "z-50",
13
+ // Background
14
+ "bg-black/50",
15
+ // Animations - open
16
+ "data-[state=open]:animate-in",
17
+ "data-[state=open]:fade-in-0",
18
+ // Animations - closed
19
+ "data-[state=closed]:animate-out",
20
+ "data-[state=closed]:fade-out-0",
21
+ );
22
+
23
+ // Dialog content styles
24
+ const dialogContentStyles = cn(
25
+ // Layout
26
+ "fixed",
27
+ "top-[50%]",
28
+ "left-[50%]",
29
+ "z-50",
30
+ "grid",
31
+ "w-full",
32
+ "max-w-[calc(100%-2rem)]",
33
+ "translate-x-[-50%]",
34
+ "translate-y-[-50%]",
35
+ "gap-4",
36
+ // Shape
37
+ "rounded-lg",
38
+ // Borders
39
+ "border",
40
+ "border-border-primary",
41
+ // Background & Colors
42
+ "bg-bg-primary",
43
+ // Spacing
44
+ "p-6",
45
+ // Shadow
46
+ "shadow-lg",
47
+ // Animation duration
48
+ "duration-200",
49
+ // Responsive
50
+ "sm:max-w-lg",
51
+ // Animations - open
52
+ "data-[state=open]:animate-in",
53
+ "data-[state=open]:fade-in-0",
54
+ "data-[state=open]:zoom-in-95",
55
+ // Animations - closed
56
+ "data-[state=closed]:animate-out",
57
+ "data-[state=closed]:fade-out-0",
58
+ "data-[state=closed]:zoom-out-95",
59
+ );
60
+
61
+ // Dialog close button styles
62
+ const dialogCloseButtonStyles = cn(
63
+ // Layout
64
+ "absolute",
65
+ "top-4",
66
+ "right-4",
67
+ // Shape
68
+ "rounded-xs",
69
+ // Opacity
70
+ "opacity-70",
71
+ "hover:opacity-100",
72
+ // Transitions
73
+ "transition-opacity",
74
+ // Focus
75
+ "focus:ring-2",
76
+ "focus:ring-utility-blue/70",
77
+ "focus:ring-offset-2",
78
+ "focus:outline-hidden",
79
+ // Disabled
80
+ "disabled:pointer-events-none",
81
+ // SVG styles
82
+ "[&_svg]:pointer-events-none",
83
+ "[&_svg]:shrink-0",
84
+ "[&_svg:not([class*='size-'])]:size-4",
85
+ // States
86
+ "data-[state=open]:bg-bg-secondary",
87
+ "data-[state=open]:text-text-secondary",
88
+ );
89
+
7
90
  function Dialog({
8
91
  ...props
9
92
  }: React.ComponentProps<typeof DialogPrimitive.Root>) {
@@ -35,10 +118,7 @@ function DialogOverlay({
35
118
  return (
36
119
  <DialogPrimitive.Overlay
37
120
  data-slot="dialog-overlay"
38
- className={cn(
39
- "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
40
- className,
41
- )}
121
+ className={cn(dialogOverlayStyles, className)}
42
122
  {...props}
43
123
  />
44
124
  );
@@ -57,17 +137,14 @@ function DialogContent({
57
137
  <DialogOverlay />
58
138
  <DialogPrimitive.Content
59
139
  data-slot="dialog-content"
60
- className={cn(
61
- "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",
62
- className,
63
- )}
140
+ className={cn(dialogContentStyles, className)}
64
141
  {...props}
65
142
  >
66
143
  {children}
67
144
  {showCloseButton && (
68
145
  <DialogPrimitive.Close
69
146
  data-slot="dialog-close"
70
- className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
147
+ className={dialogCloseButtonStyles}
71
148
  >
72
149
  <XIcon />
73
150
  <span className="sr-only">Close</span>
@@ -82,7 +159,14 @@ function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
82
159
  return (
83
160
  <div
84
161
  data-slot="dialog-header"
85
- className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
162
+ className={cn(
163
+ "flex",
164
+ "flex-col",
165
+ "gap-2",
166
+ "text-center",
167
+ "sm:text-left",
168
+ className,
169
+ )}
86
170
  {...props}
87
171
  />
88
172
  );
@@ -93,7 +177,11 @@ function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
93
177
  <div
94
178
  data-slot="dialog-footer"
95
179
  className={cn(
96
- "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
180
+ "flex",
181
+ "flex-col-reverse",
182
+ "gap-2",
183
+ "sm:flex-row",
184
+ "sm:justify-end",
97
185
  className,
98
186
  )}
99
187
  {...props}
@@ -108,7 +196,7 @@ function DialogTitle({
108
196
  return (
109
197
  <DialogPrimitive.Title
110
198
  data-slot="dialog-title"
111
- className={cn("text-lg leading-none font-semibold", className)}
199
+ className={cn("text-lg", "leading-none", "font-semibold", className)}
112
200
  {...props}
113
201
  />
114
202
  );
@@ -121,7 +209,7 @@ function DialogDescription({
121
209
  return (
122
210
  <DialogPrimitive.Description
123
211
  data-slot="dialog-description"
124
- className={cn("text-muted-foreground text-sm", className)}
212
+ className={cn("text-text-secondary", "text-sm", className)}
125
213
  {...props}
126
214
  />
127
215
  );