@multicomma/arkcn 0.1.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 (237) hide show
  1. package/README.md +78 -0
  2. package/bin/arkcn.mjs +78 -0
  3. package/cli/commands.mjs +251 -0
  4. package/cli/project.mjs +168 -0
  5. package/cli/registry.mjs +50 -0
  6. package/cli/ui.mjs +46 -0
  7. package/mcp/server.mjs +149 -0
  8. package/package.json +201 -0
  9. package/registry/base.css +680 -0
  10. package/registry/index.json +1833 -0
  11. package/registry/items/accordion.json +18 -0
  12. package/registry/items/activity-feed.json +18 -0
  13. package/registry/items/alert-dialog.json +18 -0
  14. package/registry/items/alert.json +17 -0
  15. package/registry/items/angle-slider.json +17 -0
  16. package/registry/items/app-shell.json +28 -0
  17. package/registry/items/aspect-ratio.json +13 -0
  18. package/registry/items/attachment.json +19 -0
  19. package/registry/items/avatar.json +17 -0
  20. package/registry/items/badge.json +18 -0
  21. package/registry/items/breadcrumb.json +18 -0
  22. package/registry/items/bubble.json +18 -0
  23. package/registry/items/button-group.json +19 -0
  24. package/registry/items/button.json +18 -0
  25. package/registry/items/calendar.json +19 -0
  26. package/registry/items/canvas.json +24 -0
  27. package/registry/items/card.json +15 -0
  28. package/registry/items/carousel.json +19 -0
  29. package/registry/items/cascader.json +23 -0
  30. package/registry/items/chart.json +17 -0
  31. package/registry/items/chat.json +23 -0
  32. package/registry/items/checkbox.json +18 -0
  33. package/registry/items/clipboard.json +19 -0
  34. package/registry/items/collapsible.json +15 -0
  35. package/registry/items/color-picker.json +19 -0
  36. package/registry/items/combobox.json +20 -0
  37. package/registry/items/command.json +21 -0
  38. package/registry/items/comment-thread.json +25 -0
  39. package/registry/items/context-menu.json +18 -0
  40. package/registry/items/controllable.json +14 -0
  41. package/registry/items/data-grid.json +24 -0
  42. package/registry/items/data-table-adapter.json +14 -0
  43. package/registry/items/data-table.json +32 -0
  44. package/registry/items/date-input.json +17 -0
  45. package/registry/items/dialog.json +19 -0
  46. package/registry/items/direction.json +13 -0
  47. package/registry/items/drag-preview.json +16 -0
  48. package/registry/items/drawer.json +18 -0
  49. package/registry/items/dropdown-menu.json +18 -0
  50. package/registry/items/editable.json +17 -0
  51. package/registry/items/empty.json +17 -0
  52. package/registry/items/field.json +19 -0
  53. package/registry/items/file-upload.json +19 -0
  54. package/registry/items/floating-panel.json +19 -0
  55. package/registry/items/floating-toolbar.json +16 -0
  56. package/registry/items/form.json +14 -0
  57. package/registry/items/format.json +15 -0
  58. package/registry/items/gantt.json +22 -0
  59. package/registry/items/history.json +14 -0
  60. package/registry/items/hotkeys.json +18 -0
  61. package/registry/items/hover-card.json +17 -0
  62. package/registry/items/image-cropper.json +17 -0
  63. package/registry/items/input-group.json +20 -0
  64. package/registry/items/input-otp.json +18 -0
  65. package/registry/items/input.json +15 -0
  66. package/registry/items/item.json +19 -0
  67. package/registry/items/json-tree-view.json +17 -0
  68. package/registry/items/kanban.json +26 -0
  69. package/registry/items/kbd.json +15 -0
  70. package/registry/items/label.json +15 -0
  71. package/registry/items/live-region.json +16 -0
  72. package/registry/items/marker.json +18 -0
  73. package/registry/items/marquee.json +17 -0
  74. package/registry/items/menubar.json +19 -0
  75. package/registry/items/message.json +15 -0
  76. package/registry/items/navigation-menu.json +19 -0
  77. package/registry/items/node-graph.json +22 -0
  78. package/registry/items/number-input.json +18 -0
  79. package/registry/items/pagination.json +18 -0
  80. package/registry/items/password-input.json +18 -0
  81. package/registry/items/popconfirm.json +20 -0
  82. package/registry/items/popover.json +18 -0
  83. package/registry/items/progress.json +17 -0
  84. package/registry/items/qr-code.json +17 -0
  85. package/registry/items/query-builder.json +23 -0
  86. package/registry/items/radio-group.json +17 -0
  87. package/registry/items/rating-group.json +18 -0
  88. package/registry/items/resizable.json +17 -0
  89. package/registry/items/rich-text-editor.json +37 -0
  90. package/registry/items/row-layout.json +15 -0
  91. package/registry/items/scheduler.json +23 -0
  92. package/registry/items/scroll-area.json +17 -0
  93. package/registry/items/segment-group.json +17 -0
  94. package/registry/items/select.json +19 -0
  95. package/registry/items/separator.json +15 -0
  96. package/registry/items/sheet.json +19 -0
  97. package/registry/items/sidebar.json +27 -0
  98. package/registry/items/signature-pad.json +19 -0
  99. package/registry/items/skeleton.json +15 -0
  100. package/registry/items/slider.json +17 -0
  101. package/registry/items/sonner.json +17 -0
  102. package/registry/items/spinner.json +17 -0
  103. package/registry/items/steps.json +19 -0
  104. package/registry/items/swap.json +17 -0
  105. package/registry/items/switch.json +17 -0
  106. package/registry/items/table.json +16 -0
  107. package/registry/items/tabs.json +18 -0
  108. package/registry/items/tags-input.json +18 -0
  109. package/registry/items/textarea.json +15 -0
  110. package/registry/items/time.json +14 -0
  111. package/registry/items/timer.json +18 -0
  112. package/registry/items/toc.json +17 -0
  113. package/registry/items/toggle-group.json +19 -0
  114. package/registry/items/toggle.json +18 -0
  115. package/registry/items/tooltip.json +17 -0
  116. package/registry/items/tour.json +19 -0
  117. package/registry/items/transfer-list.json +24 -0
  118. package/registry/items/tree-select.json +24 -0
  119. package/registry/items/tree-view.json +18 -0
  120. package/registry/items/use-mobile.json +13 -0
  121. package/registry/items/utils.json +17 -0
  122. package/registry/items/virtual-list.json +16 -0
  123. package/src/components/ui/accordion.tsx +111 -0
  124. package/src/components/ui/activity-feed.tsx +228 -0
  125. package/src/components/ui/alert-dialog.tsx +204 -0
  126. package/src/components/ui/alert.tsx +55 -0
  127. package/src/components/ui/angle-slider.tsx +117 -0
  128. package/src/components/ui/app-shell.tsx +985 -0
  129. package/src/components/ui/aspect-ratio.tsx +35 -0
  130. package/src/components/ui/attachment.tsx +193 -0
  131. package/src/components/ui/avatar.tsx +94 -0
  132. package/src/components/ui/badge.tsx +45 -0
  133. package/src/components/ui/breadcrumb.tsx +93 -0
  134. package/src/components/ui/bubble.tsx +119 -0
  135. package/src/components/ui/button-group.tsx +79 -0
  136. package/src/components/ui/button.tsx +65 -0
  137. package/src/components/ui/calendar.tsx +172 -0
  138. package/src/components/ui/canvas.tsx +723 -0
  139. package/src/components/ui/card.tsx +69 -0
  140. package/src/components/ui/carousel.tsx +228 -0
  141. package/src/components/ui/cascader.tsx +754 -0
  142. package/src/components/ui/chart.tsx +303 -0
  143. package/src/components/ui/chat.tsx +544 -0
  144. package/src/components/ui/checkbox.tsx +94 -0
  145. package/src/components/ui/clipboard.tsx +94 -0
  146. package/src/components/ui/collapsible.tsx +32 -0
  147. package/src/components/ui/color-picker.tsx +441 -0
  148. package/src/components/ui/combobox.tsx +400 -0
  149. package/src/components/ui/command.tsx +292 -0
  150. package/src/components/ui/comment-thread.tsx +923 -0
  151. package/src/components/ui/context-menu.tsx +331 -0
  152. package/src/components/ui/data-grid.tsx +1227 -0
  153. package/src/components/ui/data-table.tsx +993 -0
  154. package/src/components/ui/date-input.tsx +103 -0
  155. package/src/components/ui/dialog.tsx +159 -0
  156. package/src/components/ui/direction.tsx +32 -0
  157. package/src/components/ui/drawer.tsx +200 -0
  158. package/src/components/ui/dropdown-menu.tsx +329 -0
  159. package/src/components/ui/editable.tsx +90 -0
  160. package/src/components/ui/empty.tsx +86 -0
  161. package/src/components/ui/field.tsx +218 -0
  162. package/src/components/ui/file-upload.tsx +204 -0
  163. package/src/components/ui/floating-panel.tsx +199 -0
  164. package/src/components/ui/floating-toolbar.tsx +79 -0
  165. package/src/components/ui/format.tsx +22 -0
  166. package/src/components/ui/gantt.tsx +950 -0
  167. package/src/components/ui/hotkeys.tsx +340 -0
  168. package/src/components/ui/hover-card.tsx +83 -0
  169. package/src/components/ui/image-cropper.tsx +100 -0
  170. package/src/components/ui/input-group.tsx +133 -0
  171. package/src/components/ui/input-otp.tsx +82 -0
  172. package/src/components/ui/input.tsx +18 -0
  173. package/src/components/ui/item.tsx +174 -0
  174. package/src/components/ui/json-tree-view.tsx +37 -0
  175. package/src/components/ui/kanban.tsx +884 -0
  176. package/src/components/ui/kbd.tsx +20 -0
  177. package/src/components/ui/label.tsx +30 -0
  178. package/src/components/ui/live-region.tsx +54 -0
  179. package/src/components/ui/marker.tsx +66 -0
  180. package/src/components/ui/marquee.tsx +61 -0
  181. package/src/components/ui/menubar.tsx +456 -0
  182. package/src/components/ui/message.tsx +74 -0
  183. package/src/components/ui/navigation-menu.tsx +202 -0
  184. package/src/components/ui/node-graph.tsx +1723 -0
  185. package/src/components/ui/number-input.tsx +148 -0
  186. package/src/components/ui/pagination.tsx +88 -0
  187. package/src/components/ui/password-input.tsx +104 -0
  188. package/src/components/ui/popconfirm.tsx +149 -0
  189. package/src/components/ui/popover.tsx +126 -0
  190. package/src/components/ui/progress.tsx +114 -0
  191. package/src/components/ui/qr-code.tsx +51 -0
  192. package/src/components/ui/query-builder.tsx +938 -0
  193. package/src/components/ui/radio-group.tsx +108 -0
  194. package/src/components/ui/rating-group.tsx +91 -0
  195. package/src/components/ui/resizable.tsx +41 -0
  196. package/src/components/ui/rich-text-editor.tsx +845 -0
  197. package/src/components/ui/scheduler.tsx +1164 -0
  198. package/src/components/ui/scroll-area.tsx +82 -0
  199. package/src/components/ui/segment-group.tsx +95 -0
  200. package/src/components/ui/select.tsx +354 -0
  201. package/src/components/ui/separator.tsx +32 -0
  202. package/src/components/ui/sheet.tsx +130 -0
  203. package/src/components/ui/sidebar.tsx +665 -0
  204. package/src/components/ui/signature-pad.tsx +112 -0
  205. package/src/components/ui/skeleton.tsx +7 -0
  206. package/src/components/ui/slider.tsx +183 -0
  207. package/src/components/ui/sonner.tsx +37 -0
  208. package/src/components/ui/spinner.tsx +16 -0
  209. package/src/components/ui/steps.tsx +152 -0
  210. package/src/components/ui/swap.tsx +33 -0
  211. package/src/components/ui/switch.tsx +83 -0
  212. package/src/components/ui/table.tsx +72 -0
  213. package/src/components/ui/tabs.tsx +100 -0
  214. package/src/components/ui/tags-input.tsx +153 -0
  215. package/src/components/ui/textarea.tsx +17 -0
  216. package/src/components/ui/timer.tsx +67 -0
  217. package/src/components/ui/toc.tsx +64 -0
  218. package/src/components/ui/toggle-group.tsx +89 -0
  219. package/src/components/ui/toggle.tsx +46 -0
  220. package/src/components/ui/tooltip.tsx +113 -0
  221. package/src/components/ui/tour.tsx +168 -0
  222. package/src/components/ui/transfer-list.tsx +700 -0
  223. package/src/components/ui/tree-select.tsx +638 -0
  224. package/src/components/ui/tree-view.tsx +217 -0
  225. package/src/components/ui/virtual-list.tsx +343 -0
  226. package/src/hooks/use-mobile.ts +19 -0
  227. package/src/lib/controllable.ts +31 -0
  228. package/src/lib/data-table-adapter.ts +67 -0
  229. package/src/lib/drag-preview.ts +39 -0
  230. package/src/lib/form.ts +39 -0
  231. package/src/lib/history.ts +55 -0
  232. package/src/lib/row-layout.ts +81 -0
  233. package/src/lib/table.ts +483 -0
  234. package/src/lib/time.ts +37 -0
  235. package/src/lib/utils.ts +6 -0
  236. package/src/styles/arkcn.css +764 -0
  237. package/src/styles/index.css +3 -0
@@ -0,0 +1,544 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { ark } from "@ark-ui/react"
5
+ import { cva, type VariantProps } from "class-variance-authority"
6
+ import { ArrowLeftIcon, MessagesSquareIcon, SearchIcon, SendIcon } from "lucide-react"
7
+ import { cn } from "@/lib/utils"
8
+ import { useControllable } from "@/lib/controllable"
9
+
10
+ import { Button } from "@/components/ui/button"
11
+ import { ScrollArea } from "@/components/ui/scroll-area"
12
+
13
+ /* -------------------------------------------------------------------------- */
14
+ /* Root and context */
15
+ /* -------------------------------------------------------------------------- */
16
+
17
+ type ChatContextValue = {
18
+ /** Id of the selected conversation. */
19
+ value: string | null
20
+ setValue: (value: string | null) => void
21
+ /** On small screens the panel overlays the list only while this is true. */
22
+ mobileOpen: boolean
23
+ setMobileOpen: (open: boolean) => void
24
+ }
25
+
26
+ const ChatContext = React.createContext<ChatContextValue | null>(null)
27
+
28
+ function useChat(component = "Chat parts") {
29
+ const ctx = React.useContext(ChatContext)
30
+ if (!ctx) throw new Error(`${component} must be used within <Chat>`)
31
+ return ctx
32
+ }
33
+
34
+ function Chat({
35
+ className,
36
+ value: valueProp,
37
+ defaultValue = null,
38
+ onValueChange,
39
+ ...props
40
+ }: Omit<React.ComponentProps<"div">, "defaultValue"> & {
41
+ value?: string | null
42
+ defaultValue?: string | null
43
+ onValueChange?: (value: string | null) => void
44
+ }) {
45
+ const [value, setValue] = useControllable(valueProp, defaultValue, onValueChange)
46
+ const [mobileOpen, setMobileOpen] = React.useState(value !== null)
47
+ const ctx = React.useMemo(() => ({ value, setValue, mobileOpen, setMobileOpen }), [value, setValue, mobileOpen])
48
+ return (
49
+ <ChatContext.Provider value={ctx}>
50
+ <div
51
+ data-slot="chat"
52
+ data-selected={value !== null ? "" : undefined}
53
+ className={cn("relative flex h-full gap-6", className)}
54
+ {...props}
55
+ />
56
+ </ChatContext.Provider>
57
+ )
58
+ }
59
+
60
+ function ChatContextConsumer({ children }: { children: (ctx: ChatContextValue) => React.ReactNode }) {
61
+ return children(useChat("ChatContext"))
62
+ }
63
+
64
+ /* -------------------------------------------------------------------------- */
65
+ /* Sidebar: header, search, conversation list */
66
+ /* -------------------------------------------------------------------------- */
67
+
68
+ function ChatSidebar({ className, ...props }: React.ComponentProps<"div">) {
69
+ return (
70
+ <div
71
+ data-slot="chat-sidebar"
72
+ className={cn("flex w-full flex-col gap-2 sm:w-56 lg:w-72 2xl:w-80", className)}
73
+ {...props}
74
+ />
75
+ )
76
+ }
77
+
78
+ function ChatSidebarHeader({ className, ...props }: React.ComponentProps<"div">) {
79
+ return (
80
+ <div
81
+ data-slot="chat-sidebar-header"
82
+ className={cn(
83
+ "sticky top-0 z-10 -mx-4 flex flex-col gap-2 bg-background px-4 pb-3 shadow-md sm:static sm:z-auto sm:mx-0 sm:p-0 sm:shadow-none",
84
+ className
85
+ )}
86
+ {...props}
87
+ />
88
+ )
89
+ }
90
+
91
+ function ChatSidebarTitle({ className, children, ...props }: React.ComponentProps<"div">) {
92
+ return (
93
+ <div data-slot="chat-sidebar-title" className={cn("flex items-center justify-between py-2", className)} {...props}>
94
+ {children}
95
+ </div>
96
+ )
97
+ }
98
+
99
+ function ChatSidebarHeading({ className, children, ...props }: React.ComponentProps<"h1">) {
100
+ return (
101
+ <h1
102
+ data-slot="chat-sidebar-heading"
103
+ className={cn("flex items-center gap-2 text-2xl font-bold", className)}
104
+ {...props}
105
+ >
106
+ {children}
107
+ <MessagesSquareIcon className="size-5" />
108
+ </h1>
109
+ )
110
+ }
111
+
112
+ function ChatSearch({ className, ...props }: React.ComponentProps<"input">) {
113
+ return (
114
+ <label
115
+ data-slot="chat-search"
116
+ className={cn(
117
+ "flex h-9 w-full items-center gap-2 rounded-lg border border-input bg-transparent px-2.5 text-sm transition-colors has-focus-visible:border-ring has-focus-visible:ring-3 has-focus-visible:ring-ring/50 dark:bg-input/30",
118
+ className
119
+ )}
120
+ >
121
+ <SearchIcon className="size-4 shrink-0 text-muted-foreground" />
122
+ <span className="sr-only">Search</span>
123
+ <input
124
+ type="text"
125
+ data-slot="chat-search-input"
126
+ className="min-w-0 flex-1 bg-transparent outline-none placeholder:text-muted-foreground"
127
+ {...props}
128
+ />
129
+ </label>
130
+ )
131
+ }
132
+
133
+ function ChatConversationList({ className, children, ...props }: React.ComponentProps<typeof ScrollArea>) {
134
+ return (
135
+ <ScrollArea data-slot="chat-conversation-list" className={cn("-mx-3 h-full flex-1", className)} {...props}>
136
+ <div role="list" className="flex flex-col p-3 *:border-b *:border-border *:last:border-b-0">
137
+ {children}
138
+ </div>
139
+ </ScrollArea>
140
+ )
141
+ }
142
+
143
+ function ChatConversationItem({
144
+ className,
145
+ value,
146
+ onClick,
147
+ asChild,
148
+ ...props
149
+ }: React.ComponentProps<typeof ark.button> & { value: string }) {
150
+ const ctx = useChat("ChatConversationItem")
151
+ const selected = ctx.value === value
152
+ return (
153
+ <div role="listitem" className="py-1">
154
+ <ark.button
155
+ asChild={asChild}
156
+ type="button"
157
+ data-slot="chat-conversation-item"
158
+ data-selected={selected ? "" : undefined}
159
+ aria-current={selected ? "true" : undefined}
160
+ className={cn(
161
+ "group/chat-conversation-item flex w-full gap-2 rounded-md p-2 text-start text-sm outline-none hover:bg-accent hover:text-accent-foreground focus-visible:ring-3 focus-visible:ring-ring/50 data-selected:sm:bg-muted",
162
+ className
163
+ )}
164
+ onClick={(event) => {
165
+ onClick?.(event)
166
+ if (event.defaultPrevented) return
167
+ ctx.setValue(value)
168
+ ctx.setMobileOpen(true)
169
+ }}
170
+ {...props}
171
+ />
172
+ </div>
173
+ )
174
+ }
175
+
176
+ function ChatConversationInfo({ className, ...props }: React.ComponentProps<"div">) {
177
+ return <div data-slot="chat-conversation-info" className={cn("flex min-w-0 flex-col", className)} {...props} />
178
+ }
179
+
180
+ function ChatConversationName({ className, ...props }: React.ComponentProps<"span">) {
181
+ return <span data-slot="chat-conversation-name" className={cn("font-medium", className)} {...props} />
182
+ }
183
+
184
+ function ChatConversationPreview({ className, ...props }: React.ComponentProps<"span">) {
185
+ return (
186
+ <span
187
+ data-slot="chat-conversation-preview"
188
+ className={cn(
189
+ "line-clamp-2 text-muted-foreground group-hover/chat-conversation-item:text-accent-foreground/90",
190
+ className
191
+ )}
192
+ {...props}
193
+ />
194
+ )
195
+ }
196
+
197
+ /* -------------------------------------------------------------------------- */
198
+ /* Panel: header, messages, composer */
199
+ /* -------------------------------------------------------------------------- */
200
+
201
+ function ChatPanel({ className, ...props }: React.ComponentProps<"div">) {
202
+ const ctx = useChat("ChatPanel")
203
+ return (
204
+ <div
205
+ data-slot="chat-panel"
206
+ data-mobile-open={ctx.mobileOpen ? "" : undefined}
207
+ className={cn(
208
+ "absolute inset-0 inset-s-full z-50 hidden w-full flex-1 flex-col border bg-background shadow-xs data-mobile-open:inset-s-0 data-mobile-open:flex sm:static sm:z-auto sm:flex sm:rounded-md",
209
+ className
210
+ )}
211
+ {...props}
212
+ />
213
+ )
214
+ }
215
+
216
+ function ChatHeader({ className, ...props }: React.ComponentProps<"div">) {
217
+ return (
218
+ <div
219
+ data-slot="chat-header"
220
+ className={cn(
221
+ "mb-1 flex flex-none items-center justify-between gap-3 bg-card p-4 shadow-lg sm:rounded-t-md",
222
+ className
223
+ )}
224
+ {...props}
225
+ />
226
+ )
227
+ }
228
+
229
+ /** Returns to the conversation list on small screens. Polymorphic via `asChild`. */
230
+ function ChatBackTrigger({ className, onClick, children, asChild, ...props }: React.ComponentProps<typeof Button>) {
231
+ const ctx = useChat("ChatBackTrigger")
232
+ return (
233
+ <Button
234
+ data-slot="chat-back-trigger"
235
+ size="icon"
236
+ variant="ghost"
237
+ asChild={asChild}
238
+ className={cn("-ms-2 sm:hidden", className)}
239
+ onClick={(event) => {
240
+ onClick?.(event)
241
+ if (!event.defaultPrevented) ctx.setMobileOpen(false)
242
+ }}
243
+ {...props}
244
+ >
245
+ {asChild
246
+ ? children
247
+ : (children ?? (
248
+ <>
249
+ <ArrowLeftIcon className="rtl:rotate-180" />
250
+ <span className="sr-only">Back</span>
251
+ </>
252
+ ))}
253
+ </Button>
254
+ )
255
+ }
256
+
257
+ function ChatHeaderInfo({ className, ...props }: React.ComponentProps<"div">) {
258
+ return (
259
+ <div
260
+ data-slot="chat-header-info"
261
+ className={cn("flex min-w-0 items-center gap-2 lg:gap-4", className)}
262
+ {...props}
263
+ />
264
+ )
265
+ }
266
+
267
+ function ChatHeaderText({ className, ...props }: React.ComponentProps<"div">) {
268
+ return <div data-slot="chat-header-text" className={cn("flex min-w-0 flex-col", className)} {...props} />
269
+ }
270
+
271
+ function ChatHeaderTitle({ className, ...props }: React.ComponentProps<"span">) {
272
+ return <span data-slot="chat-header-title" className={cn("text-sm font-medium lg:text-base", className)} {...props} />
273
+ }
274
+
275
+ function ChatHeaderDescription({ className, ...props }: React.ComponentProps<"span">) {
276
+ return (
277
+ <span
278
+ data-slot="chat-header-description"
279
+ className={cn("line-clamp-1 max-w-32 text-xs text-muted-foreground lg:max-w-none lg:text-sm", className)}
280
+ {...props}
281
+ />
282
+ )
283
+ }
284
+
285
+ function ChatHeaderActions({ className, ...props }: React.ComponentProps<"div">) {
286
+ return (
287
+ <div
288
+ data-slot="chat-header-actions"
289
+ className={cn("-me-1 flex items-center gap-1 lg:gap-2", className)}
290
+ {...props}
291
+ />
292
+ )
293
+ }
294
+
295
+ function ChatBody({ className, ...props }: React.ComponentProps<"div">) {
296
+ return <div data-slot="chat-body" className={cn("flex flex-1 flex-col gap-2 px-4 pt-0 pb-4", className)} {...props} />
297
+ }
298
+
299
+ /**
300
+ * Bottom-anchored message stream. Render messages newest-first: the column is
301
+ * reversed so the latest message sits at the bottom and the scroll position
302
+ * stays pinned there as messages arrive.
303
+ */
304
+ function ChatMessages({ className, ...props }: React.ComponentProps<"div">) {
305
+ return (
306
+ <div data-slot="chat-messages" className="relative -me-4 flex flex-1 flex-col overflow-y-hidden">
307
+ <div
308
+ data-slot="chat-messages-viewport"
309
+ className={cn(
310
+ "flex h-40 w-full grow flex-col-reverse justify-start gap-4 overflow-y-auto py-2 pe-4 pb-4",
311
+ className
312
+ )}
313
+ {...props}
314
+ />
315
+ </div>
316
+ )
317
+ }
318
+
319
+ function ChatDateSeparator({ className, ...props }: React.ComponentProps<"div">) {
320
+ return <div data-slot="chat-date-separator" className={cn("text-center text-xs", className)} {...props} />
321
+ }
322
+
323
+ const chatMessageVariants = cva("group/chat-message max-w-72 px-3 py-2 wrap-break-word shadow-lg", {
324
+ variants: {
325
+ variant: {
326
+ sent: "self-end rounded-[16px_16px_0_16px] bg-primary/90 text-primary-foreground/75",
327
+ received: "self-start rounded-[16px_16px_16px_0] bg-muted",
328
+ },
329
+ },
330
+ defaultVariants: { variant: "received" },
331
+ })
332
+
333
+ function ChatMessage({
334
+ className,
335
+ variant = "received",
336
+ ...props
337
+ }: React.ComponentProps<"div"> & VariantProps<typeof chatMessageVariants>) {
338
+ return (
339
+ <div
340
+ data-slot="chat-message"
341
+ data-variant={variant}
342
+ className={cn(chatMessageVariants({ variant }), className)}
343
+ {...props}
344
+ />
345
+ )
346
+ }
347
+
348
+ function ChatMessageTime({ className, ...props }: React.ComponentProps<"span">) {
349
+ return (
350
+ <span
351
+ data-slot="chat-message-time"
352
+ className={cn(
353
+ "mt-1 block text-xs font-light text-foreground/75 italic group-data-[variant=sent]/chat-message:text-end group-data-[variant=sent]/chat-message:text-primary-foreground/85",
354
+ className
355
+ )}
356
+ {...props}
357
+ />
358
+ )
359
+ }
360
+
361
+ function ChatComposer({ className, ...props }: React.ComponentProps<"form">) {
362
+ return <form data-slot="chat-composer" className={cn("flex w-full flex-none gap-2", className)} {...props} />
363
+ }
364
+
365
+ function ChatComposerField({ className, ...props }: React.ComponentProps<"div">) {
366
+ return (
367
+ <div
368
+ data-slot="chat-composer-field"
369
+ className={cn(
370
+ "flex flex-1 items-center gap-2 rounded-md border border-input bg-card px-2 py-1 transition-colors has-focus-visible:border-ring has-focus-visible:ring-3 has-focus-visible:ring-ring/50 lg:gap-4",
371
+ className
372
+ )}
373
+ {...props}
374
+ />
375
+ )
376
+ }
377
+
378
+ function ChatComposerActions({ className, ...props }: React.ComponentProps<"div">) {
379
+ return <div data-slot="chat-composer-actions" className={cn("flex items-center gap-1", className)} {...props} />
380
+ }
381
+
382
+ function ChatComposerInput({ className, ...props }: React.ComponentProps<"input">) {
383
+ return (
384
+ <label className="flex-1">
385
+ <span className="sr-only">Message</span>
386
+ <input
387
+ type="text"
388
+ data-slot="chat-composer-input"
389
+ className={cn(
390
+ "h-8 w-full min-w-0 bg-transparent text-sm outline-none placeholder:text-muted-foreground",
391
+ className
392
+ )}
393
+ {...props}
394
+ />
395
+ </label>
396
+ )
397
+ }
398
+
399
+ /** Submits the composer form. Polymorphic via `asChild`. */
400
+ function ChatComposerSendTrigger({
401
+ className,
402
+ children,
403
+ asChild,
404
+ variant = "ghost",
405
+ size = "icon",
406
+ ...props
407
+ }: React.ComponentProps<typeof Button>) {
408
+ return (
409
+ <Button
410
+ data-slot="chat-composer-send-trigger"
411
+ type="submit"
412
+ variant={variant}
413
+ size={size}
414
+ asChild={asChild}
415
+ className={className}
416
+ {...props}
417
+ >
418
+ {asChild
419
+ ? children
420
+ : (children ?? (
421
+ <>
422
+ <SendIcon />
423
+ <span className="sr-only">Send</span>
424
+ </>
425
+ ))}
426
+ </Button>
427
+ )
428
+ }
429
+
430
+ /* -------------------------------------------------------------------------- */
431
+ /* Empty state */
432
+ /* -------------------------------------------------------------------------- */
433
+
434
+ function ChatEmpty({ className, ...props }: React.ComponentProps<"div">) {
435
+ return (
436
+ <div
437
+ data-slot="chat-empty"
438
+ className={cn(
439
+ "absolute inset-0 inset-s-full z-50 hidden w-full flex-1 flex-col justify-center rounded-md border bg-card shadow-xs sm:static sm:z-auto sm:flex",
440
+ className
441
+ )}
442
+ {...props}
443
+ />
444
+ )
445
+ }
446
+
447
+ function ChatEmptyContent({ className, ...props }: React.ComponentProps<"div">) {
448
+ return <div data-slot="chat-empty-content" className={cn("flex flex-col items-center gap-6", className)} {...props} />
449
+ }
450
+
451
+ function ChatEmptyIcon({ className, children, ...props }: React.ComponentProps<"div">) {
452
+ return (
453
+ <div
454
+ data-slot="chat-empty-icon"
455
+ className={cn(
456
+ "flex size-16 items-center justify-center rounded-full border-2 border-border [&_svg]:size-8",
457
+ className
458
+ )}
459
+ {...props}
460
+ >
461
+ {children ?? <MessagesSquareIcon />}
462
+ </div>
463
+ )
464
+ }
465
+
466
+ function ChatEmptyTitle({ className, ...props }: React.ComponentProps<"h2">) {
467
+ return <h2 data-slot="chat-empty-title" className={cn("text-center text-xl font-semibold", className)} {...props} />
468
+ }
469
+
470
+ function ChatEmptyDescription({ className, ...props }: React.ComponentProps<"p">) {
471
+ return (
472
+ <p
473
+ data-slot="chat-empty-description"
474
+ className={cn("text-center text-sm text-muted-foreground", className)}
475
+ {...props}
476
+ />
477
+ )
478
+ }
479
+
480
+ /* -------------------------------------------------------------------------- */
481
+ /* Helpers */
482
+ /* -------------------------------------------------------------------------- */
483
+
484
+ /** Group items by a key while preserving first-seen order of the keys. */
485
+ function groupBy<T>(items: T[], getKey: (item: T) => string): [string, T[]][] {
486
+ const groups = new Map<string, T[]>()
487
+ for (const item of items) {
488
+ const key = getKey(item)
489
+ const list = groups.get(key)
490
+ if (list) list.push(item)
491
+ else groups.set(key, [item])
492
+ }
493
+ return Array.from(groups.entries())
494
+ }
495
+
496
+ /** "Jane Doe" -> "JD"; single word -> first two letters; empty -> "?". */
497
+ function getInitials(name: string) {
498
+ const parts = name.trim().split(/\s+/).filter(Boolean)
499
+ if (parts.length === 0) return "?"
500
+ if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase()
501
+ return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase()
502
+ }
503
+
504
+ export {
505
+ Chat,
506
+ ChatBackTrigger,
507
+ ChatBody,
508
+ ChatComposer,
509
+ ChatComposerActions,
510
+ ChatComposerField,
511
+ ChatComposerInput,
512
+ ChatComposerSendTrigger,
513
+ ChatContextConsumer as ChatContext,
514
+ ChatConversationInfo,
515
+ ChatConversationItem,
516
+ ChatConversationList,
517
+ ChatConversationName,
518
+ ChatConversationPreview,
519
+ ChatDateSeparator,
520
+ ChatEmpty,
521
+ ChatEmptyContent,
522
+ ChatEmptyDescription,
523
+ ChatEmptyIcon,
524
+ ChatEmptyTitle,
525
+ ChatHeader,
526
+ ChatHeaderActions,
527
+ ChatHeaderDescription,
528
+ ChatHeaderInfo,
529
+ ChatHeaderText,
530
+ ChatHeaderTitle,
531
+ ChatMessage,
532
+ ChatMessageTime,
533
+ ChatMessages,
534
+ ChatPanel,
535
+ ChatSearch,
536
+ ChatSidebar,
537
+ ChatSidebarHeader,
538
+ ChatSidebarHeading,
539
+ ChatSidebarTitle,
540
+ chatMessageVariants,
541
+ getInitials,
542
+ groupBy,
543
+ useChat,
544
+ }
@@ -0,0 +1,94 @@
1
+ import * as React from "react"
2
+ import { cn } from "@/lib/utils"
3
+ import { Checkbox as CheckboxPrimitive } from "@ark-ui/react"
4
+ import { CheckIcon, MinusIcon } from "lucide-react"
5
+
6
+ const checkboxControlClassName =
7
+ "relative flex size-4 shrink-0 items-center justify-center rounded-[4px] border border-input transition-colors outline-none group-has-disabled/field:opacity-50 group-has-[:focus-visible]/field-label:ring-0 group-has-[:focus-visible]/field-label:not-data-checked:border-input after:absolute after:-inset-x-3 after:-inset-y-2 data-focus-visible:border-ring data-focus-visible:ring-3 data-focus-visible:ring-ring/50 data-disabled:cursor-not-allowed data-disabled:opacity-50 data-invalid:border-destructive data-invalid:ring-3 data-invalid:ring-destructive/20 data-invalid:data-checked:border-primary dark:bg-input/30 dark:data-invalid:border-destructive/50 dark:data-invalid:ring-destructive/40 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground data-[state=indeterminate]:border-primary data-[state=indeterminate]:bg-primary data-[state=indeterminate]:text-primary-foreground group-has-[:focus-visible]/field-label:data-checked:border-primary dark:data-checked:bg-primary"
8
+
9
+ /** `id` is omitted: set part ids through the root `ids` prop so Ark's internal lookups keep working. */
10
+ function Checkbox({ className, children, ...props }: Omit<React.ComponentProps<typeof CheckboxPrimitive.Root>, "id">) {
11
+ return (
12
+ <CheckboxPrimitive.Root
13
+ data-slot="checkbox"
14
+ className="group/checkbox peer inline-flex items-center gap-2"
15
+ {...props}
16
+ >
17
+ <CheckboxControl className={className}>
18
+ <CheckboxIndicator>
19
+ <CheckIcon />
20
+ </CheckboxIndicator>
21
+ <CheckboxIndicator indeterminate>
22
+ <MinusIcon />
23
+ </CheckboxIndicator>
24
+ </CheckboxControl>
25
+ {children && <CheckboxLabel>{children}</CheckboxLabel>}
26
+ <CheckboxHiddenInput />
27
+ </CheckboxPrimitive.Root>
28
+ )
29
+ }
30
+
31
+ /** `id` is omitted: set part ids through the root `ids` prop so Ark's internal lookups keep working. */
32
+ function CheckboxRoot({ ...props }: Omit<React.ComponentProps<typeof CheckboxPrimitive.Root>, "id">) {
33
+ return <CheckboxPrimitive.Root data-slot="checkbox" {...props} />
34
+ }
35
+
36
+ function CheckboxContext({ ...props }: React.ComponentProps<typeof CheckboxPrimitive.Context>) {
37
+ return <CheckboxPrimitive.Context {...props} />
38
+ }
39
+
40
+ /** `id` is omitted: set part ids through the root `ids` prop so Ark's internal lookups keep working. */
41
+ function CheckboxControl({ className, ...props }: Omit<React.ComponentProps<typeof CheckboxPrimitive.Control>, "id">) {
42
+ return (
43
+ <CheckboxPrimitive.Control
44
+ data-slot="checkbox-control"
45
+ className={cn(checkboxControlClassName, className)}
46
+ {...props}
47
+ />
48
+ )
49
+ }
50
+
51
+ function CheckboxIndicator({ className, ...props }: React.ComponentProps<typeof CheckboxPrimitive.Indicator>) {
52
+ return (
53
+ <CheckboxPrimitive.Indicator
54
+ data-slot="checkbox-indicator"
55
+ className={cn("grid place-content-center text-current transition-none [&>svg]:size-3.5", className)}
56
+ {...props}
57
+ />
58
+ )
59
+ }
60
+
61
+ function CheckboxLabel({ className, ...props }: React.ComponentProps<typeof CheckboxPrimitive.Label>) {
62
+ return (
63
+ <CheckboxPrimitive.Label
64
+ data-slot="checkbox-label"
65
+ className={cn("text-sm leading-none select-none data-disabled:opacity-50", className)}
66
+ {...props}
67
+ />
68
+ )
69
+ }
70
+
71
+ /** `id` is omitted: set part ids through the root `ids` prop so Ark's internal lookups keep working. */
72
+ function CheckboxHiddenInput({ ...props }: Omit<React.ComponentProps<typeof CheckboxPrimitive.HiddenInput>, "id">) {
73
+ return <CheckboxPrimitive.HiddenInput {...props} />
74
+ }
75
+
76
+ function CheckboxGroup({ className, ...props }: React.ComponentProps<typeof CheckboxPrimitive.Group>) {
77
+ return <CheckboxPrimitive.Group data-slot="checkbox-group" className={cn("grid gap-2", className)} {...props} />
78
+ }
79
+
80
+ function CheckboxGroupProvider({ ...props }: React.ComponentProps<typeof CheckboxPrimitive.GroupProvider>) {
81
+ return <CheckboxPrimitive.GroupProvider {...props} />
82
+ }
83
+
84
+ export {
85
+ Checkbox,
86
+ CheckboxContext,
87
+ CheckboxControl,
88
+ CheckboxGroup,
89
+ CheckboxHiddenInput,
90
+ CheckboxIndicator,
91
+ CheckboxLabel,
92
+ CheckboxRoot,
93
+ CheckboxGroupProvider,
94
+ }