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

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 (239) hide show
  1. package/dist/bundle.css +687 -446
  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 +13 -2
  20. package/dist/src/components/code-editor/index.d.ts.map +1 -1
  21. package/dist/src/components/code-editor/index.js +161 -20
  22. package/dist/src/components/code-editor/index.js.map +1 -1
  23. package/dist/src/components/code-editor.stories.js +3 -1
  24. package/dist/src/components/code-editor.stories.js.map +1 -1
  25. package/dist/src/components/request-line-editor.d.ts +11 -35
  26. package/dist/src/components/request-line-editor.d.ts.map +1 -1
  27. package/dist/src/components/request-line-editor.js +51 -49
  28. package/dist/src/components/request-line-editor.js.map +1 -1
  29. package/dist/src/components/request-line-editor.stories.d.ts.map +1 -1
  30. package/dist/src/components/request-line-editor.stories.js +17 -53
  31. package/dist/src/components/request-line-editor.stories.js.map +1 -1
  32. package/dist/src/components/tree-view.d.ts +16 -0
  33. package/dist/src/components/tree-view.d.ts.map +1 -0
  34. package/dist/src/components/tree-view.js +67 -0
  35. package/dist/src/components/tree-view.js.map +1 -0
  36. package/dist/src/components/tree-view.stories.d.ts +13 -0
  37. package/dist/src/components/tree-view.stories.d.ts.map +1 -0
  38. package/dist/src/components/tree-view.stories.js +274 -0
  39. package/dist/src/components/tree-view.stories.js.map +1 -0
  40. package/dist/src/icons.d.ts +3 -0
  41. package/dist/src/icons.d.ts.map +1 -0
  42. package/dist/src/icons.js +47 -0
  43. package/dist/src/icons.js.map +1 -0
  44. package/dist/src/index.css +42 -3
  45. package/dist/src/index.d.ts +1 -1
  46. package/dist/src/index.d.ts.map +1 -1
  47. package/dist/src/index.js +1 -1
  48. package/dist/src/index.js.map +1 -1
  49. package/dist/src/shadcn/components/ui/accordion.d.ts.map +1 -1
  50. package/dist/src/shadcn/components/ui/accordion.js +23 -5
  51. package/dist/src/shadcn/components/ui/accordion.js.map +1 -1
  52. package/dist/src/shadcn/components/ui/alert.d.ts.map +1 -1
  53. package/dist/src/shadcn/components/ui/alert.js +12 -5
  54. package/dist/src/shadcn/components/ui/alert.js.map +1 -1
  55. package/dist/src/shadcn/components/ui/avatar.d.ts.map +1 -1
  56. package/dist/src/shadcn/components/ui/avatar.js +4 -3
  57. package/dist/src/shadcn/components/ui/avatar.js.map +1 -1
  58. package/dist/src/shadcn/components/ui/badge.d.ts.map +1 -1
  59. package/dist/src/shadcn/components/ui/badge.js +16 -5
  60. package/dist/src/shadcn/components/ui/badge.js.map +1 -1
  61. package/dist/src/shadcn/components/ui/breadcrumb.d.ts.map +1 -1
  62. package/dist/src/shadcn/components/ui/breadcrumb.js +6 -6
  63. package/dist/src/shadcn/components/ui/breadcrumb.js.map +1 -1
  64. package/dist/src/shadcn/components/ui/button.d.ts.map +1 -1
  65. package/dist/src/shadcn/components/ui/button.js +19 -11
  66. package/dist/src/shadcn/components/ui/button.js.map +1 -1
  67. package/dist/src/shadcn/components/ui/card.d.ts.map +1 -1
  68. package/dist/src/shadcn/components/ui/card.js +14 -6
  69. package/dist/src/shadcn/components/ui/card.js.map +1 -1
  70. package/dist/src/shadcn/components/ui/checkbox.d.ts.map +1 -1
  71. package/dist/src/shadcn/components/ui/checkbox.js +20 -5
  72. package/dist/src/shadcn/components/ui/checkbox.js.map +1 -1
  73. package/dist/src/shadcn/components/ui/checkbox.stories.d.ts.map +1 -1
  74. package/dist/src/shadcn/components/ui/checkbox.stories.js +44 -35
  75. package/dist/src/shadcn/components/ui/checkbox.stories.js.map +1 -1
  76. package/dist/src/shadcn/components/ui/combobox.d.ts +18 -0
  77. package/dist/src/shadcn/components/ui/combobox.d.ts.map +1 -0
  78. package/dist/src/shadcn/components/ui/combobox.js +121 -0
  79. package/dist/src/shadcn/components/ui/combobox.js.map +1 -0
  80. package/dist/src/shadcn/components/ui/combobox.stories.d.ts +11 -0
  81. package/dist/src/shadcn/components/ui/combobox.stories.d.ts.map +1 -0
  82. package/dist/src/shadcn/components/ui/combobox.stories.js +16 -0
  83. package/dist/src/shadcn/components/ui/combobox.stories.js.map +1 -0
  84. package/dist/src/shadcn/components/ui/command.d.ts.map +1 -1
  85. package/dist/src/shadcn/components/ui/command.js +73 -12
  86. package/dist/src/shadcn/components/ui/command.js.map +1 -1
  87. package/dist/src/shadcn/components/ui/command.stories.js +0 -1
  88. package/dist/src/shadcn/components/ui/command.stories.js.map +1 -1
  89. package/dist/src/shadcn/components/ui/dialog.d.ts.map +1 -1
  90. package/dist/src/shadcn/components/ui/dialog.js +35 -7
  91. package/dist/src/shadcn/components/ui/dialog.js.map +1 -1
  92. package/dist/src/shadcn/components/ui/drawer.d.ts.map +1 -1
  93. package/dist/src/shadcn/components/ui/drawer.js +26 -5
  94. package/dist/src/shadcn/components/ui/drawer.js.map +1 -1
  95. package/dist/src/shadcn/components/ui/dropdown-menu.d.ts.map +1 -1
  96. package/dist/src/shadcn/components/ui/dropdown-menu.js +12 -1
  97. package/dist/src/shadcn/components/ui/dropdown-menu.js.map +1 -1
  98. package/dist/src/shadcn/components/ui/form.d.ts.map +1 -1
  99. package/dist/src/shadcn/components/ui/form.js +12 -4
  100. package/dist/src/shadcn/components/ui/form.js.map +1 -1
  101. package/dist/src/shadcn/components/ui/input.d.ts.map +1 -1
  102. package/dist/src/shadcn/components/ui/input.js +87 -16
  103. package/dist/src/shadcn/components/ui/input.js.map +1 -1
  104. package/dist/src/shadcn/components/ui/label.d.ts.map +1 -1
  105. package/dist/src/shadcn/components/ui/label.js +8 -1
  106. package/dist/src/shadcn/components/ui/label.js.map +1 -1
  107. package/dist/src/shadcn/components/ui/menubar.d.ts.map +1 -1
  108. package/dist/src/shadcn/components/ui/menubar.js +35 -13
  109. package/dist/src/shadcn/components/ui/menubar.js.map +1 -1
  110. package/dist/src/shadcn/components/ui/pagination.d.ts.map +1 -1
  111. package/dist/src/shadcn/components/ui/pagination.js +6 -6
  112. package/dist/src/shadcn/components/ui/pagination.js.map +1 -1
  113. package/dist/src/shadcn/components/ui/popover.d.ts.map +1 -1
  114. package/dist/src/shadcn/components/ui/popover.js +12 -1
  115. package/dist/src/shadcn/components/ui/popover.js.map +1 -1
  116. package/dist/src/shadcn/components/ui/progress.d.ts.map +1 -1
  117. package/dist/src/shadcn/components/ui/progress.js +6 -2
  118. package/dist/src/shadcn/components/ui/progress.js.map +1 -1
  119. package/dist/src/shadcn/components/ui/radio-group.d.ts.map +1 -1
  120. package/dist/src/shadcn/components/ui/radio-group.js +11 -6
  121. package/dist/src/shadcn/components/ui/radio-group.js.map +1 -1
  122. package/dist/src/shadcn/components/ui/radio-group.stories.d.ts.map +1 -1
  123. package/dist/src/shadcn/components/ui/radio-group.stories.js +57 -34
  124. package/dist/src/shadcn/components/ui/radio-group.stories.js.map +1 -1
  125. package/dist/src/shadcn/components/ui/scroll-area.d.ts.map +1 -1
  126. package/dist/src/shadcn/components/ui/scroll-area.js +9 -3
  127. package/dist/src/shadcn/components/ui/scroll-area.js.map +1 -1
  128. package/dist/src/shadcn/components/ui/select.d.ts.map +1 -1
  129. package/dist/src/shadcn/components/ui/select.js +49 -14
  130. package/dist/src/shadcn/components/ui/select.js.map +1 -1
  131. package/dist/src/shadcn/components/ui/select.stories.d.ts.map +1 -1
  132. package/dist/src/shadcn/components/ui/select.stories.js +1 -4
  133. package/dist/src/shadcn/components/ui/select.stories.js.map +1 -1
  134. package/dist/src/shadcn/components/ui/separator.d.ts.map +1 -1
  135. package/dist/src/shadcn/components/ui/separator.js +7 -1
  136. package/dist/src/shadcn/components/ui/separator.js.map +1 -1
  137. package/dist/src/shadcn/components/ui/sidebar.d.ts.map +1 -1
  138. package/dist/src/shadcn/components/ui/sidebar.js +20 -6
  139. package/dist/src/shadcn/components/ui/sidebar.js.map +1 -1
  140. package/dist/src/shadcn/components/ui/skeleton.d.ts.map +1 -1
  141. package/dist/src/shadcn/components/ui/skeleton.js +3 -1
  142. package/dist/src/shadcn/components/ui/skeleton.js.map +1 -1
  143. package/dist/src/shadcn/components/ui/slider.d.ts.map +1 -1
  144. package/dist/src/shadcn/components/ui/slider.js +34 -4
  145. package/dist/src/shadcn/components/ui/slider.js.map +1 -1
  146. package/dist/src/shadcn/components/ui/sonner.d.ts +16 -1
  147. package/dist/src/shadcn/components/ui/sonner.d.ts.map +1 -1
  148. package/dist/src/shadcn/components/ui/sonner.js +23 -3
  149. package/dist/src/shadcn/components/ui/sonner.js.map +1 -1
  150. package/dist/src/shadcn/components/ui/sonner.stories.d.ts.map +1 -1
  151. package/dist/src/shadcn/components/ui/sonner.stories.js +19 -11
  152. package/dist/src/shadcn/components/ui/sonner.stories.js.map +1 -1
  153. package/dist/src/shadcn/components/ui/switch.d.ts.map +1 -1
  154. package/dist/src/shadcn/components/ui/switch.js +18 -2
  155. package/dist/src/shadcn/components/ui/switch.js.map +1 -1
  156. package/dist/src/shadcn/components/ui/table.d.ts.map +1 -1
  157. package/dist/src/shadcn/components/ui/table.js +12 -8
  158. package/dist/src/shadcn/components/ui/table.js.map +1 -1
  159. package/dist/src/shadcn/components/ui/tabs.d.ts +21 -3
  160. package/dist/src/shadcn/components/ui/tabs.d.ts.map +1 -1
  161. package/dist/src/shadcn/components/ui/tabs.js +314 -9
  162. package/dist/src/shadcn/components/ui/tabs.js.map +1 -1
  163. package/dist/src/shadcn/components/ui/tabs.stories.d.ts.map +1 -1
  164. package/dist/src/shadcn/components/ui/tabs.stories.js +50 -1
  165. package/dist/src/shadcn/components/ui/tabs.stories.js.map +1 -1
  166. package/dist/src/shadcn/components/ui/textarea.d.ts.map +1 -1
  167. package/dist/src/shadcn/components/ui/textarea.js +15 -1
  168. package/dist/src/shadcn/components/ui/textarea.js.map +1 -1
  169. package/dist/src/shadcn/components/ui/toggle-group.d.ts.map +1 -1
  170. package/dist/src/shadcn/components/ui/toggle-group.js +6 -2
  171. package/dist/src/shadcn/components/ui/toggle-group.js.map +1 -1
  172. package/dist/src/shadcn/components/ui/toggle.d.ts.map +1 -1
  173. package/dist/src/shadcn/components/ui/toggle.js +18 -6
  174. package/dist/src/shadcn/components/ui/toggle.js.map +1 -1
  175. package/dist/src/shadcn/components/ui/tooltip.d.ts.map +1 -1
  176. package/dist/src/shadcn/components/ui/tooltip.js +11 -1
  177. package/dist/src/shadcn/components/ui/tooltip.js.map +1 -1
  178. package/dist/src/shadcn/components/ui/tree.d.ts +20 -0
  179. package/dist/src/shadcn/components/ui/tree.d.ts.map +1 -0
  180. package/dist/src/shadcn/components/ui/tree.js +111 -0
  181. package/dist/src/shadcn/components/ui/tree.js.map +1 -0
  182. package/package.json +9 -2
  183. package/src/components/code-editor/http/grammar/http.grammar +74 -0
  184. package/src/components/code-editor/http/grammar/http.terms.ts +9 -0
  185. package/src/components/code-editor/http/grammar/http.test.ts +110 -0
  186. package/src/components/code-editor/http/grammar/http.ts +21 -0
  187. package/src/components/code-editor/http/index.ts +87 -0
  188. package/src/components/code-editor/index.tsx +182 -21
  189. package/src/components/code-editor.stories.tsx +1 -1
  190. package/src/components/request-line-editor.stories.tsx +17 -27
  191. package/src/components/request-line-editor.tsx +72 -61
  192. package/src/components/tree-view.stories.tsx +260 -0
  193. package/src/components/tree-view.tsx +101 -0
  194. package/src/icons.tsx +45 -0
  195. package/src/index.css +42 -3
  196. package/src/index.tsx +1 -1
  197. package/src/shadcn/components/ui/accordion.tsx +66 -8
  198. package/src/shadcn/components/ui/alert.tsx +53 -15
  199. package/src/shadcn/components/ui/avatar.tsx +17 -6
  200. package/src/shadcn/components/ui/badge.tsx +67 -18
  201. package/src/shadcn/components/ui/breadcrumb.tsx +35 -7
  202. package/src/shadcn/components/ui/button.tsx +118 -57
  203. package/src/shadcn/components/ui/card.tsx +44 -13
  204. package/src/shadcn/components/ui/checkbox.stories.tsx +20 -24
  205. package/src/shadcn/components/ui/checkbox.tsx +45 -4
  206. package/src/shadcn/components/ui/combobox.stories.tsx +19 -0
  207. package/src/shadcn/components/ui/combobox.tsx +142 -0
  208. package/src/shadcn/components/ui/command.stories.tsx +1 -1
  209. package/src/shadcn/components/ui/command.tsx +192 -36
  210. package/src/shadcn/components/ui/dialog.tsx +101 -13
  211. package/src/shadcn/components/ui/drawer.tsx +93 -18
  212. package/src/shadcn/components/ui/dropdown-menu.tsx +38 -9
  213. package/src/shadcn/components/ui/form.tsx +16 -4
  214. package/src/shadcn/components/ui/input.tsx +281 -29
  215. package/src/shadcn/components/ui/label.tsx +21 -4
  216. package/src/shadcn/components/ui/menubar.tsx +188 -43
  217. package/src/shadcn/components/ui/pagination.tsx +12 -6
  218. package/src/shadcn/components/ui/popover.tsx +35 -4
  219. package/src/shadcn/components/ui/progress.tsx +21 -5
  220. package/src/shadcn/components/ui/radio-group.stories.tsx +22 -14
  221. package/src/shadcn/components/ui/radio-group.tsx +42 -5
  222. package/src/shadcn/components/ui/scroll-area.tsx +33 -5
  223. package/src/shadcn/components/ui/select.stories.tsx +0 -2
  224. package/src/shadcn/components/ui/select.tsx +184 -33
  225. package/src/shadcn/components/ui/separator.tsx +15 -5
  226. package/src/shadcn/components/ui/sidebar.tsx +68 -26
  227. package/src/shadcn/components/ui/skeleton.tsx +4 -1
  228. package/src/shadcn/components/ui/slider.tsx +82 -11
  229. package/src/shadcn/components/ui/sonner.stories.tsx +19 -15
  230. package/src/shadcn/components/ui/sonner.tsx +53 -3
  231. package/src/shadcn/components/ui/switch.tsx +53 -7
  232. package/src/shadcn/components/ui/table.tsx +38 -11
  233. package/src/shadcn/components/ui/tabs.stories.tsx +32 -0
  234. package/src/shadcn/components/ui/tabs.tsx +455 -17
  235. package/src/shadcn/components/ui/textarea.tsx +42 -4
  236. package/src/shadcn/components/ui/toggle-group.tsx +27 -5
  237. package/src/shadcn/components/ui/toggle.tsx +59 -18
  238. package/src/shadcn/components/ui/tooltip.tsx +33 -8
  239. package/src/shadcn/components/ui/tree.tsx +200 -0
@@ -2,16 +2,29 @@ import type * as React from "react";
2
2
 
3
3
  import { cn } from "#shadcn/lib/utils";
4
4
 
5
+ // Card styles
6
+ const cardStyles = cn(
7
+ // Layout
8
+ "flex",
9
+ "flex-col",
10
+ "gap-6",
11
+ // Shape
12
+ "rounded-xl",
13
+ // Borders
14
+ "border",
15
+ "border-border-primary",
16
+ // Background & Colors
17
+ "bg-bg-primary",
18
+ "text-text-primary",
19
+ // Spacing
20
+ "py-6",
21
+ // Shadow
22
+ "shadow-sm",
23
+ );
24
+
5
25
  function Card({ className, ...props }: React.ComponentProps<"div">) {
6
26
  return (
7
- <div
8
- data-slot="card"
9
- className={cn(
10
- "bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
11
- className,
12
- )}
13
- {...props}
14
- />
27
+ <div data-slot="card" className={cn(cardStyles, className)} {...props} />
15
28
  );
16
29
  }
17
30
 
@@ -20,7 +33,15 @@ function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
20
33
  <div
21
34
  data-slot="card-header"
22
35
  className={cn(
23
- "@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
36
+ "@container/card-header",
37
+ "grid",
38
+ "auto-rows-min",
39
+ "grid-rows-[auto_auto]",
40
+ "items-start",
41
+ "gap-1.5",
42
+ "px-6",
43
+ "has-data-[slot=card-action]:grid-cols-[1fr_auto]",
44
+ "[.border-b]:pb-6",
24
45
  className,
25
46
  )}
26
47
  {...props}
@@ -32,7 +53,7 @@ function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
32
53
  return (
33
54
  <div
34
55
  data-slot="card-title"
35
- className={cn("leading-none font-semibold", className)}
56
+ className={cn("leading-none", "font-semibold", className)}
36
57
  {...props}
37
58
  />
38
59
  );
@@ -42,7 +63,7 @@ function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
42
63
  return (
43
64
  <div
44
65
  data-slot="card-description"
45
- className={cn("text-muted-foreground text-sm", className)}
66
+ className={cn("text-text-secondary", "text-sm", className)}
46
67
  {...props}
47
68
  />
48
69
  );
@@ -53,7 +74,11 @@ function CardAction({ className, ...props }: React.ComponentProps<"div">) {
53
74
  <div
54
75
  data-slot="card-action"
55
76
  className={cn(
56
- "col-start-2 row-span-2 row-start-1 self-start justify-self-end",
77
+ "col-start-2",
78
+ "row-span-2",
79
+ "row-start-1",
80
+ "self-start",
81
+ "justify-self-end",
57
82
  className,
58
83
  )}
59
84
  {...props}
@@ -75,7 +100,13 @@ function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
75
100
  return (
76
101
  <div
77
102
  data-slot="card-footer"
78
- className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
103
+ className={cn(
104
+ "flex",
105
+ "items-center",
106
+ "px-6",
107
+ "[.border-t]:pt-6",
108
+ className,
109
+ )}
79
110
  {...props}
80
111
  />
81
112
  );
@@ -14,36 +14,32 @@ export const Demo = {
14
14
  <div className="flex flex-col gap-6">
15
15
  <div className="flex items-center gap-3">
16
16
  <Checkbox id="terms" />
17
- <Label htmlFor="terms">Accept terms and conditions</Label>
17
+ <Label htmlFor="terms">Unchecked</Label>
18
18
  </div>
19
- <div className="flex items-start gap-3">
19
+ <div className="flex items-center gap-3">
20
20
  <Checkbox id="terms-2" defaultChecked />
21
- <div className="grid gap-2">
22
- <Label htmlFor="terms-2">Accept terms and conditions</Label>
23
- <p className="text-muted-foreground text-sm">
24
- By clicking this checkbox, you agree to the terms and conditions.
25
- </p>
26
- </div>
21
+ <Label htmlFor="terms-2">Checked</Label>
22
+ </div>
23
+ <div className="flex items-center gap-3">
24
+ <Checkbox id="indeterminate" checked="indeterminate" />
25
+ <Label htmlFor="indeterminate">Indeterminate</Label>
26
+ </div>
27
+ <div className="flex items-center gap-3">
28
+ <Checkbox id="disabled" disabled />
29
+ <Label htmlFor="disabled">Disabled unchecked</Label>
27
30
  </div>
28
- <div className="flex items-start gap-3">
29
- <Checkbox id="toggle" disabled />
30
- <Label htmlFor="toggle">Enable notifications</Label>
31
+ <div className="flex items-center gap-3">
32
+ <Checkbox id="disabled-checked" disabled defaultChecked />
33
+ <Label htmlFor="disabled-checked">Disabled checked</Label>
31
34
  </div>
32
- <Label className="hover:bg-accent/50 flex items-start gap-3 rounded-lg border p-3 has-[[aria-checked=true]]:border-blue-600 has-[[aria-checked=true]]:bg-blue-50 dark:has-[[aria-checked=true]]:border-blue-900 dark:has-[[aria-checked=true]]:bg-blue-950">
35
+ <div className="flex items-center gap-3">
33
36
  <Checkbox
34
- id="toggle-2"
35
- defaultChecked
36
- className="data-[state=checked]:border-blue-600 data-[state=checked]:bg-blue-600 data-[state=checked]:text-white dark:data-[state=checked]:border-blue-700 dark:data-[state=checked]:bg-blue-700"
37
+ id="disabled-indeterminate"
38
+ disabled
39
+ checked="indeterminate"
37
40
  />
38
- <div className="grid gap-1.5 font-normal">
39
- <p className="text-sm leading-none font-medium">
40
- Enable notifications
41
- </p>
42
- <p className="text-muted-foreground text-sm">
43
- You can enable or disable notifications at any time.
44
- </p>
45
- </div>
46
- </Label>
41
+ <Label htmlFor="disabled-indeterminate">Disabled indeterminate</Label>
42
+ </div>
47
43
  </div>
48
44
  ),
49
45
  } satisfies Story;
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
3
- import { CheckIcon } from "lucide-react";
3
+ import { CheckIcon, MinusIcon } from "lucide-react";
4
4
  import type * as React from "react";
5
5
 
6
6
  import { cn } from "#shadcn/lib/utils";
@@ -13,16 +13,57 @@ function Checkbox({
13
13
  <CheckboxPrimitive.Root
14
14
  data-slot="checkbox"
15
15
  className={cn(
16
- "peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
16
+ // Base styles
17
+ "peer",
18
+ "size-5",
19
+ "shrink-0",
20
+ "rounded-md",
21
+ "border-[1.5px]",
22
+ "transition-all",
23
+ "duration-200",
24
+ "outline-none",
25
+ "cursor-pointer",
26
+ "text-white",
27
+ // Click animation
28
+ "active:scale-90",
29
+ "active:duration-75",
30
+ // Default state
31
+ "border-border-primary",
32
+ "bg-transparent",
33
+ "hover:bg-bg-tertiary",
34
+ // Checked state
35
+ "data-[state=checked]:bg-bg-link",
36
+ "data-[state=checked]:border-border-link",
37
+ "data-[state=checked]:text-white",
38
+ // Indeterminate state
39
+ "data-[state=indeterminate]:bg-fg-link",
40
+ "data-[state=indeterminate]:border-fg-link",
41
+ "data-[state=indeterminate]:text-white",
42
+ // Disabled states
43
+ "disabled:cursor-not-allowed",
44
+ "disabled:active:scale-100",
45
+ "disabled:border-border-secondary",
46
+ "disabled:bg-transparent",
47
+ "disabled:data-[state=checked]:bg-fg-tertiary",
48
+ "disabled:data-[state=checked]:border-fg-tertiary",
49
+ "disabled:data-[state=indeterminate]:bg-fg-tertiary",
50
+ "disabled:data-[state=indeterminate]:border-fg-tertiary",
51
+ // Focus state
52
+ "focus-visible:ring-2",
53
+ "focus-visible:ring-utility-blue/70",
17
54
  className,
18
55
  )}
19
56
  {...props}
20
57
  >
21
58
  <CheckboxPrimitive.Indicator
22
59
  data-slot="checkbox-indicator"
23
- className="flex items-center justify-center text-current transition-none"
60
+ className="flex items-center justify-center text-white"
24
61
  >
25
- <CheckIcon className="size-3.5" />
62
+ {props.checked === "indeterminate" ? (
63
+ <MinusIcon className="size-3.5" style={{ strokeWidth: 3 }} />
64
+ ) : (
65
+ <CheckIcon className="size-3.5" style={{ strokeWidth: 3 }} />
66
+ )}
26
67
  </CheckboxPrimitive.Indicator>
27
68
  </CheckboxPrimitive.Root>
28
69
  );
@@ -0,0 +1,19 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+ import { ComboboxDemo } from "./combobox";
3
+
4
+ const meta = {
5
+ title: "Component/Combobox",
6
+ component: ComboboxDemo,
7
+ argTypes: {},
8
+ } satisfies Meta;
9
+ export default meta;
10
+
11
+ type Story = StoryObj<typeof meta>;
12
+
13
+ export const Default = {
14
+ render: () => (
15
+ <div className="w-[560px]">
16
+ <ComboboxDemo />
17
+ </div>
18
+ ),
19
+ } satisfies Story;
@@ -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
  );