@copilotkitnext/react 0.0.3 → 0.0.4

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 (48) hide show
  1. package/package.json +3 -3
  2. package/.turbo/turbo-build$colon$css.log +0 -9
  3. package/.turbo/turbo-build.log +0 -30
  4. package/.turbo/turbo-check-types.log +0 -7
  5. package/.turbo/turbo-lint.log +0 -78
  6. package/.turbo/turbo-test.log +0 -79
  7. package/postcss.config.js +0 -7
  8. package/src/__tests__/setup.ts +0 -2
  9. package/src/components/chat/CopilotChat.tsx +0 -90
  10. package/src/components/chat/CopilotChatAssistantMessage.tsx +0 -478
  11. package/src/components/chat/CopilotChatAudioRecorder.tsx +0 -157
  12. package/src/components/chat/CopilotChatInput.tsx +0 -596
  13. package/src/components/chat/CopilotChatMessageView.tsx +0 -85
  14. package/src/components/chat/CopilotChatToolCallsView.tsx +0 -43
  15. package/src/components/chat/CopilotChatUserMessage.tsx +0 -337
  16. package/src/components/chat/CopilotChatView.tsx +0 -385
  17. package/src/components/chat/__tests__/CopilotChatAssistantMessage.test.tsx +0 -684
  18. package/src/components/chat/__tests__/CopilotChatInput.test.tsx +0 -531
  19. package/src/components/chat/__tests__/setup.ts +0 -1
  20. package/src/components/chat/index.ts +0 -35
  21. package/src/components/index.ts +0 -4
  22. package/src/components/ui/button.tsx +0 -123
  23. package/src/components/ui/dropdown-menu.tsx +0 -257
  24. package/src/components/ui/tooltip.tsx +0 -59
  25. package/src/hooks/index.ts +0 -6
  26. package/src/hooks/use-agent-context.tsx +0 -17
  27. package/src/hooks/use-agent.tsx +0 -48
  28. package/src/hooks/use-frontend-tool.tsx +0 -46
  29. package/src/hooks/use-human-in-the-loop.tsx +0 -76
  30. package/src/hooks/use-render-tool-call.tsx +0 -81
  31. package/src/index.ts +0 -4
  32. package/src/lib/__tests__/completePartialMarkdown.test.ts +0 -495
  33. package/src/lib/__tests__/renderSlot.test.tsx +0 -610
  34. package/src/lib/slots.tsx +0 -55
  35. package/src/lib/utils.ts +0 -6
  36. package/src/providers/CopilotChatConfigurationProvider.tsx +0 -81
  37. package/src/providers/CopilotKitProvider.tsx +0 -269
  38. package/src/providers/__tests__/CopilotKitProvider.test.tsx +0 -487
  39. package/src/providers/__tests__/CopilotKitProvider.wildcard.test.tsx +0 -261
  40. package/src/providers/index.ts +0 -14
  41. package/src/styles/globals.css +0 -302
  42. package/src/types/frontend-tool.ts +0 -8
  43. package/src/types/human-in-the-loop.ts +0 -33
  44. package/src/types/index.ts +0 -3
  45. package/src/types/react-tool-call-render.ts +0 -29
  46. package/tailwind.config.js +0 -9
  47. package/tsconfig.json +0 -23
  48. package/tsup.config.ts +0 -19
@@ -1,531 +0,0 @@
1
- import React from "react";
2
- import { render, screen, fireEvent } from "@testing-library/react";
3
- import { vi } from "vitest";
4
- import { CopilotChatInput } from "../CopilotChatInput";
5
- import { CopilotChatConfigurationProvider } from "../../../providers/CopilotChatConfigurationProvider";
6
-
7
- // Mock onSubmitMessage function to track calls
8
- const mockOnSubmitMessage = vi.fn();
9
-
10
- // Helper to render components with context provider
11
- const renderWithProvider = (component: React.ReactElement) => {
12
- return render(
13
- <CopilotChatConfigurationProvider>
14
- {component}
15
- </CopilotChatConfigurationProvider>
16
- );
17
- };
18
-
19
- // Clear mocks before each test
20
- beforeEach(() => {
21
- mockOnSubmitMessage.mockClear();
22
- });
23
-
24
- describe("CopilotChatInput", () => {
25
- it("renders with default components and styling", () => {
26
- const mockOnChange = vi.fn();
27
- renderWithProvider(
28
- <CopilotChatInput
29
- value=""
30
- onChange={mockOnChange}
31
- onSubmitMessage={mockOnSubmitMessage}
32
- />
33
- );
34
-
35
- const input = screen.getByPlaceholderText("Type a message...");
36
- const button = screen.getByRole("button");
37
-
38
- expect(input).toBeDefined();
39
- expect(button).toBeDefined();
40
- expect((button as HTMLButtonElement).disabled).toBe(true); // Should be disabled when input is empty
41
- });
42
-
43
- it("calls onSubmitMessage with trimmed text when Enter is pressed", () => {
44
- const mockOnChange = vi.fn();
45
- renderWithProvider(
46
- <CopilotChatInput
47
- value=" hello world "
48
- onChange={mockOnChange}
49
- onSubmitMessage={mockOnSubmitMessage}
50
- />
51
- );
52
-
53
- const input = screen.getByPlaceholderText("Type a message...");
54
- fireEvent.keyDown(input, { key: "Enter", shiftKey: false });
55
-
56
- expect(mockOnSubmitMessage).toHaveBeenCalledWith("hello world");
57
- });
58
-
59
- it("calls onSubmitMessage when button is clicked", () => {
60
- const mockOnChange = vi.fn();
61
- renderWithProvider(
62
- <CopilotChatInput
63
- value="test message"
64
- onChange={mockOnChange}
65
- onSubmitMessage={mockOnSubmitMessage}
66
- />
67
- );
68
-
69
- const button = screen.getByRole("button");
70
- fireEvent.click(button);
71
-
72
- expect(mockOnSubmitMessage).toHaveBeenCalledWith("test message");
73
- });
74
-
75
- it("does not send when Enter is pressed with Shift key", () => {
76
- const mockOnChange = vi.fn();
77
- renderWithProvider(
78
- <CopilotChatInput
79
- value="test"
80
- onChange={mockOnChange}
81
- onSubmitMessage={mockOnSubmitMessage}
82
- />
83
- );
84
-
85
- const input = screen.getByPlaceholderText("Type a message...");
86
- fireEvent.keyDown(input, { key: "Enter", shiftKey: true });
87
-
88
- expect(mockOnSubmitMessage).not.toHaveBeenCalled();
89
- });
90
-
91
- it("does not send empty or whitespace-only messages", () => {
92
- const mockOnChange = vi.fn();
93
-
94
- // Test empty string
95
- const { rerender } = renderWithProvider(
96
- <CopilotChatInput
97
- value=""
98
- onChange={mockOnChange}
99
- onSubmitMessage={mockOnSubmitMessage}
100
- />
101
- );
102
-
103
- const button = screen.getByRole("button");
104
- fireEvent.click(button);
105
- expect(mockOnSubmitMessage).not.toHaveBeenCalled();
106
-
107
- // Test whitespace only
108
- rerender(
109
- <CopilotChatConfigurationProvider>
110
- <CopilotChatInput
111
- value=" "
112
- onChange={mockOnChange}
113
- onSubmitMessage={mockOnSubmitMessage}
114
- />
115
- </CopilotChatConfigurationProvider>
116
- );
117
- fireEvent.click(button);
118
- expect(mockOnSubmitMessage).not.toHaveBeenCalled();
119
- });
120
-
121
- it("enables button based on value prop", () => {
122
- const mockOnChange = vi.fn();
123
-
124
- // Test with empty value
125
- const { rerender } = renderWithProvider(
126
- <CopilotChatInput
127
- value=""
128
- onChange={mockOnChange}
129
- onSubmitMessage={mockOnSubmitMessage}
130
- />
131
- );
132
-
133
- const button = screen.getByRole("button");
134
- expect((button as HTMLButtonElement).disabled).toBe(true);
135
-
136
- // Test with non-empty value
137
- rerender(
138
- <CopilotChatConfigurationProvider>
139
- <CopilotChatInput
140
- value="hello"
141
- onChange={mockOnChange}
142
- onSubmitMessage={mockOnSubmitMessage}
143
- />
144
- </CopilotChatConfigurationProvider>
145
- );
146
- expect((button as HTMLButtonElement).disabled).toBe(false);
147
-
148
- // Test with empty value again
149
- rerender(
150
- <CopilotChatConfigurationProvider>
151
- <CopilotChatInput
152
- value=""
153
- onChange={mockOnChange}
154
- onSubmitMessage={mockOnSubmitMessage}
155
- />
156
- </CopilotChatConfigurationProvider>
157
- );
158
- expect((button as HTMLButtonElement).disabled).toBe(true);
159
- });
160
-
161
- it("accepts custom slot classes", () => {
162
- const mockOnChange = vi.fn();
163
- const { container } = renderWithProvider(
164
- <CopilotChatInput
165
- value=""
166
- onChange={mockOnChange}
167
- onSubmitMessage={mockOnSubmitMessage}
168
- className="custom-container"
169
- textArea="custom-textarea"
170
- sendButton="custom-button"
171
- />
172
- );
173
-
174
- const containerDiv = container.firstChild as HTMLElement;
175
- const input = screen.getByPlaceholderText("Type a message...");
176
- const button = screen.getByRole("button");
177
-
178
- expect(containerDiv.classList.contains("custom-container")).toBe(true);
179
- expect(input.classList.contains("custom-textarea")).toBe(true);
180
- expect(button.classList.contains("custom-button")).toBe(true);
181
- });
182
-
183
- it("accepts custom components via slots", () => {
184
- const mockOnChange = vi.fn();
185
- const CustomButton = (
186
- props: React.ButtonHTMLAttributes<HTMLButtonElement>
187
- ) => (
188
- <button {...props} data-testid="custom-button">
189
- Send Now
190
- </button>
191
- );
192
-
193
- renderWithProvider(
194
- <CopilotChatInput
195
- value=""
196
- onChange={mockOnChange}
197
- onSubmitMessage={mockOnSubmitMessage}
198
- sendButton={CustomButton}
199
- />
200
- );
201
-
202
- const customButton = screen.getByTestId("custom-button");
203
- expect(customButton).toBeDefined();
204
- expect(customButton.textContent?.includes("Send Now")).toBe(true);
205
- });
206
-
207
- it("supports custom layout via children render prop", () => {
208
- const mockOnChange = vi.fn();
209
- renderWithProvider(
210
- <CopilotChatInput
211
- value=""
212
- onChange={mockOnChange}
213
- onSubmitMessage={mockOnSubmitMessage}
214
- >
215
- {({ textArea: TextArea, sendButton: SendButton }) => (
216
- <div data-testid="custom-layout">
217
- Custom Layout:
218
- {SendButton}
219
- {TextArea}
220
- </div>
221
- )}
222
- </CopilotChatInput>
223
- );
224
-
225
- const customLayout = screen.getByTestId("custom-layout");
226
- expect(customLayout).toBeDefined();
227
- expect(customLayout.textContent?.includes("Custom Layout:")).toBe(true);
228
- });
229
-
230
- it("shows cancel and finish buttons in transcribe mode", () => {
231
- const { container } = renderWithProvider(
232
- <CopilotChatInput
233
- mode="transcribe"
234
- onSubmitMessage={mockOnSubmitMessage}
235
- onStartTranscribe={() => {}}
236
- onCancelTranscribe={() => {}}
237
- onFinishTranscribe={() => {}}
238
- onAddFile={() => {}}
239
- />
240
- );
241
-
242
- // Should show cancel button (X icon) - find by svg class
243
- const cancelIcon = container.querySelector("svg.lucide-x");
244
- expect(cancelIcon).toBeDefined();
245
-
246
- // Should show finish button (checkmark icon) - find by svg class
247
- const finishIcon = container.querySelector("svg.lucide-check");
248
- expect(finishIcon).toBeDefined();
249
-
250
- // Should show cancel button (X icon) and finish button (check icon)
251
- const cancelButton = container.querySelector("svg.lucide-x");
252
- const finishButton = container.querySelector("svg.lucide-check");
253
- expect(cancelButton).toBeDefined();
254
- expect(finishButton).toBeDefined();
255
-
256
- // Should NOT show transcribe button (mic icon) in transcribe mode
257
- const transcribeIcon = container.querySelector("svg.lucide-mic");
258
- expect(transcribeIcon).toBeNull();
259
-
260
- // Should NOT show send button (arrow-up icon) in transcribe mode
261
- const sendIcon = container.querySelector("svg.lucide-arrow-up");
262
- expect(sendIcon).toBeNull();
263
- });
264
-
265
- it("disables add and tools buttons in transcribe mode", () => {
266
- const { container } = renderWithProvider(
267
- <CopilotChatInput
268
- mode="transcribe"
269
- onSubmitMessage={mockOnSubmitMessage}
270
- onStartTranscribe={() => {}}
271
- onCancelTranscribe={() => {}}
272
- onFinishTranscribe={() => {}}
273
- onAddFile={() => {}}
274
- toolsMenu={[{ label: "Test Tool", action: () => {} }]}
275
- />
276
- );
277
-
278
- // Add button should be disabled (find by Plus icon)
279
- const addIcon = container.querySelector("svg.lucide-plus");
280
- const addButton = addIcon?.closest("button");
281
- expect((addButton as HTMLButtonElement).disabled).toBe(true);
282
-
283
- // Tools button should be disabled (find by "Tools" text)
284
- const toolsButton = screen.getByRole("button", { name: /tools/i });
285
- expect((toolsButton as HTMLButtonElement).disabled).toBe(true);
286
- });
287
-
288
- it("shows recording indicator instead of textarea in transcribe mode", () => {
289
- const { container } = renderWithProvider(
290
- <CopilotChatInput
291
- mode="transcribe"
292
- onSubmitMessage={mockOnSubmitMessage}
293
- onStartTranscribe={() => {}}
294
- onCancelTranscribe={() => {}}
295
- onFinishTranscribe={() => {}}
296
- onAddFile={() => {}}
297
- />
298
- );
299
-
300
- // Should show recording indicator (canvas element)
301
- const recordingIndicator = container.querySelector("canvas");
302
- expect(recordingIndicator).toBeDefined();
303
-
304
- // Should NOT show textarea in transcribe mode
305
- expect(screen.queryByRole("textbox")).toBeNull();
306
- });
307
-
308
- it("shows textarea in input mode", () => {
309
- const { container } = renderWithProvider(
310
- <CopilotChatInput
311
- mode="input"
312
- onSubmitMessage={mockOnSubmitMessage}
313
- onStartTranscribe={() => {}}
314
- onCancelTranscribe={() => {}}
315
- onFinishTranscribe={() => {}}
316
- onAddFile={() => {}}
317
- />
318
- );
319
-
320
- // Should show textarea in input mode
321
- expect(screen.getByRole("textbox")).toBeDefined();
322
-
323
- // Should NOT show recording indicator (red div)
324
- const recordingIndicator = container.querySelector(".bg-red-500");
325
- expect(recordingIndicator).toBeNull();
326
- });
327
-
328
- // Controlled component tests
329
- describe("Controlled component behavior", () => {
330
- it("displays the provided value prop", () => {
331
- const mockOnChange = vi.fn();
332
- const mockOnSubmitMessage = vi.fn();
333
-
334
- renderWithProvider(
335
- <CopilotChatInput
336
- value="test value"
337
- onChange={mockOnChange}
338
- onSubmitMessage={mockOnSubmitMessage}
339
- />
340
- );
341
-
342
- const input = screen.getByRole("textbox");
343
- expect((input as HTMLTextAreaElement).value).toBe("test value");
344
- });
345
-
346
- it("calls onChange when user types", () => {
347
- const mockOnChange = vi.fn();
348
- const mockOnSubmitMessage = vi.fn();
349
-
350
- renderWithProvider(
351
- <CopilotChatInput
352
- value=""
353
- onChange={mockOnChange}
354
- onSubmitMessage={mockOnSubmitMessage}
355
- />
356
- );
357
-
358
- const input = screen.getByRole("textbox");
359
- fireEvent.change(input, { target: { value: "new text" } });
360
-
361
- expect(mockOnChange).toHaveBeenCalledWith("new text");
362
- });
363
-
364
- it("calls onSubmitMessage when form is submitted", () => {
365
- const mockOnChange = vi.fn();
366
- const mockOnSubmitMessage = vi.fn();
367
-
368
- renderWithProvider(
369
- <CopilotChatInput
370
- value="hello world"
371
- onChange={mockOnChange}
372
- onSubmitMessage={mockOnSubmitMessage}
373
- />
374
- );
375
-
376
- const input = screen.getByRole("textbox");
377
- fireEvent.keyDown(input, { key: "Enter", shiftKey: false });
378
-
379
- expect(mockOnSubmitMessage).toHaveBeenCalledWith("hello world");
380
- });
381
-
382
- it("calls onSubmitMessage when send button is clicked", () => {
383
- const mockOnChange = vi.fn();
384
- const mockOnSubmitMessage = vi.fn();
385
-
386
- renderWithProvider(
387
- <CopilotChatInput
388
- value="test message"
389
- onChange={mockOnChange}
390
- onSubmitMessage={mockOnSubmitMessage}
391
- />
392
- );
393
-
394
- const button = screen.getByRole("button");
395
- fireEvent.click(button);
396
-
397
- expect(mockOnSubmitMessage).toHaveBeenCalledWith("test message");
398
- });
399
-
400
- it("trims whitespace when submitting", () => {
401
- const mockOnChange = vi.fn();
402
- const mockOnSubmitMessage = vi.fn();
403
-
404
- renderWithProvider(
405
- <CopilotChatInput
406
- value=" hello world "
407
- onChange={mockOnChange}
408
- onSubmitMessage={mockOnSubmitMessage}
409
- />
410
- );
411
-
412
- const input = screen.getByRole("textbox");
413
- fireEvent.keyDown(input, { key: "Enter", shiftKey: false });
414
-
415
- expect(mockOnSubmitMessage).toHaveBeenCalledWith("hello world");
416
- });
417
-
418
- it("does not submit empty or whitespace-only messages", () => {
419
- const mockOnChange = vi.fn();
420
- const mockOnSubmitMessage = vi.fn();
421
-
422
- renderWithProvider(
423
- <CopilotChatInput
424
- value=" "
425
- onChange={mockOnChange}
426
- onSubmitMessage={mockOnSubmitMessage}
427
- />
428
- );
429
-
430
- const button = screen.getByRole("button");
431
- fireEvent.click(button);
432
-
433
- expect(mockOnSubmitMessage).not.toHaveBeenCalled();
434
- });
435
-
436
- it("disables send button when onSubmitMessage is not provided", () => {
437
- const mockOnChange = vi.fn();
438
-
439
- renderWithProvider(
440
- <CopilotChatInput value="some text" onChange={mockOnChange} />
441
- );
442
-
443
- const button = screen.getByRole("button");
444
- expect((button as HTMLButtonElement).disabled).toBe(true);
445
- });
446
-
447
- it("disables send button when value is empty", () => {
448
- const mockOnChange = vi.fn();
449
- const mockOnSubmitMessage = vi.fn();
450
-
451
- renderWithProvider(
452
- <CopilotChatInput
453
- value=""
454
- onChange={mockOnChange}
455
- onSubmitMessage={mockOnSubmitMessage}
456
- />
457
- );
458
-
459
- const button = screen.getByRole("button");
460
- expect((button as HTMLButtonElement).disabled).toBe(true);
461
- });
462
-
463
- it("enables send button when value has content and onSubmitMessage is provided", () => {
464
- const mockOnChange = vi.fn();
465
- const mockOnSubmitMessage = vi.fn();
466
-
467
- renderWithProvider(
468
- <CopilotChatInput
469
- value="hello"
470
- onChange={mockOnChange}
471
- onSubmitMessage={mockOnSubmitMessage}
472
- />
473
- );
474
-
475
- const button = screen.getByRole("button");
476
- expect((button as HTMLButtonElement).disabled).toBe(false);
477
- });
478
-
479
- it("works as a fully controlled component", () => {
480
- const mockOnChange = vi.fn();
481
- const mockOnSubmitMessage = vi.fn();
482
-
483
- const { rerender } = renderWithProvider(
484
- <CopilotChatInput
485
- value="initial"
486
- onChange={mockOnChange}
487
- onSubmitMessage={mockOnSubmitMessage}
488
- />
489
- );
490
-
491
- const input = screen.getByRole("textbox");
492
- expect((input as HTMLTextAreaElement).value).toBe("initial");
493
-
494
- // Simulate parent component updating the value
495
- rerender(
496
- <CopilotChatConfigurationProvider>
497
- <CopilotChatInput
498
- value="updated"
499
- onChange={mockOnChange}
500
- onSubmitMessage={mockOnSubmitMessage}
501
- />
502
- </CopilotChatConfigurationProvider>
503
- );
504
-
505
- expect((input as HTMLTextAreaElement).value).toBe("updated");
506
- });
507
-
508
- it("does not clear input after submission when controlled", () => {
509
- const mockOnChange = vi.fn();
510
- const mockOnSubmitMessage = vi.fn();
511
-
512
- renderWithProvider(
513
- <CopilotChatInput
514
- value="test message"
515
- onChange={mockOnChange}
516
- onSubmitMessage={mockOnSubmitMessage}
517
- />
518
- );
519
-
520
- const input = screen.getByRole("textbox");
521
- const button = screen.getByRole("button");
522
-
523
- fireEvent.click(button);
524
-
525
- // In controlled mode, the component should not clear the input
526
- // It's up to the parent to manage the value
527
- expect((input as HTMLTextAreaElement).value).toBe("test message");
528
- expect(mockOnSubmitMessage).toHaveBeenCalledWith("test message");
529
- });
530
- });
531
- });
@@ -1 +0,0 @@
1
- import "@testing-library/jest-dom";
@@ -1,35 +0,0 @@
1
- export {
2
- default as CopilotChatInput,
3
- type CopilotChatInputProps,
4
- type ToolsMenuItem,
5
- } from "./CopilotChatInput";
6
-
7
- export {
8
- default as CopilotChatAssistantMessage,
9
- type CopilotChatAssistantMessageProps,
10
- } from "./CopilotChatAssistantMessage";
11
-
12
- export {
13
- default as CopilotChatUserMessage,
14
- type CopilotChatUserMessageProps,
15
- } from "./CopilotChatUserMessage";
16
-
17
- export {
18
- CopilotChatAudioRecorder,
19
- type AudioRecorderState,
20
- AudioRecorderError,
21
- } from "./CopilotChatAudioRecorder";
22
-
23
- export {
24
- default as CopilotChatMessageView,
25
- type CopilotChatMessageViewProps,
26
- } from "./CopilotChatMessageView";
27
-
28
- export {
29
- default as CopilotChatToolCallsView,
30
- type CopilotChatToolCallsViewProps,
31
- } from "./CopilotChatToolCallsView";
32
-
33
- export { default as CopilotChatView, type CopilotChatViewProps } from "./CopilotChatView";
34
-
35
- export { CopilotChat, type CopilotChatProps } from "./CopilotChat";
@@ -1,4 +0,0 @@
1
- // React components for CopilotKit2
2
- // Components will be added here
3
-
4
- export * from "./chat";
@@ -1,123 +0,0 @@
1
- import * as React from "react";
2
- import { Slot } from "@radix-ui/react-slot";
3
- import { cva, type VariantProps } from "class-variance-authority";
4
-
5
- import { cn } from "@/lib/utils";
6
-
7
- const buttonVariants = cva(
8
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
9
- {
10
- variants: {
11
- variant: {
12
- default:
13
- "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
14
- destructive:
15
- "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
16
- outline:
17
- "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
18
- secondary:
19
- "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
20
- ghost:
21
- "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50 cursor-pointer",
22
- link: "text-primary underline-offset-4 hover:underline",
23
- assistantMessageToolbarButton: [
24
- "cursor-pointer",
25
- // Background and text
26
- "p-0 text-[rgb(93,93,93)] hover:bg-[#E8E8E8]",
27
- // Dark mode - lighter gray for better contrast
28
- "dark:text-[rgb(243,243,243)] dark:hover:bg-[#303030]",
29
- // Shape and sizing
30
- "h-8 w-8",
31
- // Interactions
32
- "transition-colors",
33
- // Hover states
34
- "hover:text-[rgb(93,93,93)]",
35
- "dark:hover:text-[rgb(243,243,243)]",
36
- ],
37
- chatInputToolbarPrimary: [
38
- "cursor-pointer",
39
- // Background and text
40
- "bg-black text-white",
41
- // Dark mode
42
- "dark:bg-white dark:text-black dark:focus-visible:outline-white",
43
- // Shape and sizing
44
- "rounded-full",
45
- // Interactions
46
- "transition-colors",
47
- // Focus states
48
- "focus:outline-none",
49
- // Hover states
50
- "hover:opacity-70 disabled:hover:opacity-100",
51
- // Disabled states
52
- "disabled:cursor-not-allowed disabled:bg-[#00000014] disabled:text-[rgb(13,13,13)]",
53
- "dark:disabled:bg-[#454545] dark:disabled:text-white ",
54
- ],
55
- chatInputToolbarSecondary: [
56
- "cursor-pointer",
57
- // Background and text
58
- "bg-transparent text-[#444444]",
59
- // Dark mode
60
- "dark:text-white dark:border-[#404040]",
61
- // Shape and sizing
62
- "rounded-full",
63
- // Interactions
64
- "transition-colors",
65
- // Focus states
66
- "focus:outline-none",
67
- // Hover states
68
- "hover:bg-[#f8f8f8] hover:text-[#333333]",
69
- "dark:hover:bg-[#404040] dark:hover:text-[#FFFFFF]",
70
- // Disabled states
71
- "disabled:cursor-not-allowed disabled:opacity-50",
72
- "disabled:hover:bg-transparent disabled:hover:text-[#444444]",
73
- "dark:disabled:hover:bg-transparent dark:disabled:hover:text-[#CCCCCC]",
74
- ],
75
- },
76
- size: {
77
- default: "h-9 px-4 py-2 has-[>svg]:px-3",
78
- sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
79
- lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
80
- icon: "size-9",
81
- chatInputToolbarIcon: [
82
- // Shape and sizing
83
- "h-9 w-9 rounded-full",
84
- ],
85
- chatInputToolbarIconLabel: [
86
- // Shape and sizing
87
- "h-9 px-3 rounded-full",
88
- // Layout
89
- "gap-2",
90
- // Typography
91
- "font-normal",
92
- ],
93
- },
94
- },
95
- defaultVariants: {
96
- variant: "default",
97
- size: "default",
98
- },
99
- }
100
- );
101
-
102
- function Button({
103
- className,
104
- variant,
105
- size,
106
- asChild = false,
107
- ...props
108
- }: React.ComponentProps<"button"> &
109
- VariantProps<typeof buttonVariants> & {
110
- asChild?: boolean;
111
- }) {
112
- const Comp = asChild ? Slot : "button";
113
-
114
- return (
115
- <Comp
116
- data-slot="button"
117
- className={cn(buttonVariants({ variant, size, className }))}
118
- {...props}
119
- />
120
- );
121
- }
122
-
123
- export { Button, buttonVariants };