@copilotkit/react-ui 0.1.0 → 0.3.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 (58) hide show
  1. package/.turbo/turbo-build.log +13 -15
  2. package/CHANGELOG.md +19 -0
  3. package/dist/index.css +1 -1
  4. package/dist/index.d.ts +36 -2
  5. package/dist/index.js +48 -10
  6. package/dist/index.mjs +26 -0
  7. package/package.json +39 -8
  8. package/src/components/chat-components/chat-list.tsx +32 -0
  9. package/src/components/chat-components/chat-message-actions.tsx +40 -0
  10. package/src/components/chat-components/chat-message.tsx +74 -0
  11. package/src/components/chat-components/chat-panel.tsx +77 -0
  12. package/src/components/chat-components/chat-scroll-anchor.tsx +29 -0
  13. package/src/components/chat-components/clear-history.tsx +73 -0
  14. package/src/components/chat-components/copilot-chat.tsx +61 -0
  15. package/src/components/chat-components/default-empty-screen.tsx +62 -0
  16. package/src/components/chat-components/external-link.tsx +29 -0
  17. package/src/components/chat-components/markdown.tsx +9 -0
  18. package/src/components/chat-components/prompt-form.tsx +91 -0
  19. package/src/components/chat-components/theme-toggle.tsx +31 -0
  20. package/src/components/chat-components/toaster.tsx +3 -0
  21. package/src/components/chat-components/ui/alert-dialog.tsx +150 -0
  22. package/src/components/chat-components/ui/badge.tsx +36 -0
  23. package/src/components/chat-components/ui/button.tsx +57 -0
  24. package/src/components/chat-components/ui/codeblock.tsx +142 -0
  25. package/src/components/chat-components/ui/dialog.tsx +128 -0
  26. package/src/components/chat-components/ui/dropdown-menu.tsx +128 -0
  27. package/src/components/chat-components/ui/icons.tsx +507 -0
  28. package/src/components/chat-components/ui/input.tsx +25 -0
  29. package/src/components/chat-components/ui/label.tsx +26 -0
  30. package/src/components/chat-components/ui/select.tsx +119 -0
  31. package/src/components/chat-components/ui/separator.tsx +31 -0
  32. package/src/components/chat-components/ui/sheet.tsx +122 -0
  33. package/src/components/chat-components/ui/switch.tsx +29 -0
  34. package/src/components/chat-components/ui/textarea.tsx +24 -0
  35. package/src/components/chat-components/ui/tooltip.tsx +30 -0
  36. package/src/components/index.ts +7 -0
  37. package/src/components/sidebar/copilot-sidebar-ui-provider.tsx +74 -0
  38. package/src/components/sidebar/copilot-sidebar.tsx +40 -0
  39. package/src/components/sidebar/sidebar-context.tsx +11 -0
  40. package/src/context/index.ts +1 -0
  41. package/src/hooks/index.ts +1 -0
  42. package/src/hooks/use-at-bottom.tsx +23 -0
  43. package/src/hooks/use-copy-to-clipboard.tsx +33 -0
  44. package/src/hooks/use-enter-submit.tsx +23 -0
  45. package/src/index.tsx +4 -3
  46. package/src/lib/utils.ts +43 -0
  47. package/src/types/index.ts +1 -0
  48. package/src/types/types.ts +18 -0
  49. package/tailwind.config.js +1 -1
  50. package/tsconfig.json +1 -1
  51. package/dist/Button.d.ts +0 -3
  52. package/dist/Button.js +0 -10
  53. package/dist/Card.d.ts +0 -7
  54. package/dist/Card.js +0 -10
  55. package/dist/chunk-6OZR7L23.js +0 -7
  56. package/dist/chunk-FGO3LSHH.js +0 -7
  57. package/src/Button.tsx +0 -16
  58. package/src/Card.tsx +0 -27
@@ -0,0 +1,57 @@
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 rounded-md text-sm font-medium shadow ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default:
13
+ 'bg-primary text-primary-foreground shadow-md hover:bg-primary/90',
14
+ destructive:
15
+ 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
16
+ outline:
17
+ 'border border-input hover:bg-accent hover:text-accent-foreground',
18
+ secondary:
19
+ 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
20
+ ghost: 'shadow-none hover:bg-accent hover:text-accent-foreground',
21
+ link: 'text-primary underline-offset-4 shadow-none hover:underline'
22
+ },
23
+ size: {
24
+ default: 'h-8 px-4 py-2',
25
+ sm: 'h-8 rounded-md px-3',
26
+ lg: 'h-11 rounded-md px-8',
27
+ icon: 'h-8 w-8 p-0'
28
+ }
29
+ },
30
+ defaultVariants: {
31
+ variant: 'default',
32
+ size: 'default'
33
+ }
34
+ }
35
+ )
36
+
37
+ export interface ButtonProps
38
+ extends React.ButtonHTMLAttributes<HTMLButtonElement>,
39
+ VariantProps<typeof buttonVariants> {
40
+ asChild?: boolean
41
+ }
42
+
43
+ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
44
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
45
+ const Comp = asChild ? Slot : 'button'
46
+ return (
47
+ <Comp
48
+ className={cn(buttonVariants({ variant, size, className }))}
49
+ ref={ref}
50
+ {...props}
51
+ />
52
+ )
53
+ }
54
+ )
55
+ Button.displayName = 'Button'
56
+
57
+ export { Button, buttonVariants }
@@ -0,0 +1,142 @@
1
+ 'use client'
2
+
3
+ import { FC, memo } from 'react'
4
+ import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
5
+ import { coldarkDark } from 'react-syntax-highlighter/dist/cjs/styles/prism'
6
+
7
+ import { useCopyToClipboard } from '../../../hooks/use-copy-to-clipboard'
8
+ import { IconCheck, IconCopy, IconDownload } from './icons'
9
+ import { Button } from './button'
10
+
11
+ interface Props {
12
+ language: string
13
+ value: string
14
+ }
15
+
16
+ interface languageMap {
17
+ [key: string]: string | undefined
18
+ }
19
+
20
+ export const programmingLanguages: languageMap = {
21
+ javascript: '.js',
22
+ python: '.py',
23
+ java: '.java',
24
+ c: '.c',
25
+ cpp: '.cpp',
26
+ 'c++': '.cpp',
27
+ 'c#': '.cs',
28
+ ruby: '.rb',
29
+ php: '.php',
30
+ swift: '.swift',
31
+ 'objective-c': '.m',
32
+ kotlin: '.kt',
33
+ typescript: '.ts',
34
+ go: '.go',
35
+ perl: '.pl',
36
+ rust: '.rs',
37
+ scala: '.scala',
38
+ haskell: '.hs',
39
+ lua: '.lua',
40
+ shell: '.sh',
41
+ sql: '.sql',
42
+ html: '.html',
43
+ css: '.css'
44
+ // add more file extensions here, make sure the key is same as language prop in CodeBlock.tsx component
45
+ }
46
+
47
+ export const generateRandomString = (length: number, lowercase = false) => {
48
+ const chars = 'ABCDEFGHJKLMNPQRSTUVWXY3456789' // excluding similar looking characters like Z, 2, I, 1, O, 0
49
+ let result = ''
50
+ for (let i = 0; i < length; i++) {
51
+ result += chars.charAt(Math.floor(Math.random() * chars.length))
52
+ }
53
+ return lowercase ? result.toLowerCase() : result
54
+ }
55
+
56
+ const CodeBlock: FC<Props> = memo(({ language, value }) => {
57
+ const { isCopied, copyToClipboard } = useCopyToClipboard({ timeout: 2000 })
58
+
59
+ const downloadAsFile = () => {
60
+ if (typeof window === 'undefined') {
61
+ return
62
+ }
63
+ const fileExtension = programmingLanguages[language] || '.file'
64
+ const suggestedFileName = `file-${generateRandomString(
65
+ 3,
66
+ true
67
+ )}${fileExtension}`
68
+ const fileName = window.prompt('Enter file name' || '', suggestedFileName)
69
+
70
+ if (!fileName) {
71
+ // User pressed cancel on prompt.
72
+ return
73
+ }
74
+
75
+ const blob = new Blob([value], { type: 'text/plain' })
76
+ const url = URL.createObjectURL(blob)
77
+ const link = document.createElement('a')
78
+ link.download = fileName
79
+ link.href = url
80
+ link.style.display = 'none'
81
+ document.body.appendChild(link)
82
+ link.click()
83
+ document.body.removeChild(link)
84
+ URL.revokeObjectURL(url)
85
+ }
86
+
87
+ const onCopy = () => {
88
+ if (isCopied) return
89
+ copyToClipboard(value)
90
+ }
91
+
92
+ return (
93
+ <div className="codeblock relative w-full bg-zinc-950 font-sans">
94
+ <div className="flex w-full items-center justify-between bg-zinc-800 px-6 py-2 pr-4 text-zinc-100">
95
+ <span className="text-xs lowercase">{language}</span>
96
+ <div className="flex items-center space-x-1">
97
+ <Button
98
+ variant="ghost"
99
+ className="hover:bg-zinc-800 focus-visible:ring-1 focus-visible:ring-slate-700 focus-visible:ring-offset-0"
100
+ onClick={downloadAsFile}
101
+ size="icon"
102
+ >
103
+ <IconDownload />
104
+ <span className="sr-only">Download</span>
105
+ </Button>
106
+ <Button
107
+ variant="ghost"
108
+ size="icon"
109
+ className="text-xs hover:bg-zinc-800 focus-visible:ring-1 focus-visible:ring-slate-700 focus-visible:ring-offset-0"
110
+ onClick={onCopy}
111
+ >
112
+ {isCopied ? <IconCheck /> : <IconCopy />}
113
+ <span className="sr-only">Copy code</span>
114
+ </Button>
115
+ </div>
116
+ </div>
117
+ <SyntaxHighlighter
118
+ language={language}
119
+ style={coldarkDark}
120
+ PreTag="div"
121
+ showLineNumbers
122
+ customStyle={{
123
+ margin: 0,
124
+ width: '100%',
125
+ background: 'transparent',
126
+ padding: '1.5rem 1rem'
127
+ }}
128
+ codeTagProps={{
129
+ style: {
130
+ fontSize: '0.9rem',
131
+ fontFamily: 'var(--font-mono)'
132
+ }
133
+ }}
134
+ >
135
+ {value}
136
+ </SyntaxHighlighter>
137
+ </div>
138
+ )
139
+ })
140
+ CodeBlock.displayName = 'CodeBlock'
141
+
142
+ export { CodeBlock }
@@ -0,0 +1,128 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import * as DialogPrimitive from '@radix-ui/react-dialog'
5
+
6
+ import { cn } from '../../../lib/utils'
7
+ import { IconClose } from './icons'
8
+
9
+ const Dialog = DialogPrimitive.Root
10
+
11
+ const DialogTrigger = DialogPrimitive.Trigger
12
+
13
+ const DialogPortal = ({
14
+ className,
15
+ children,
16
+ ...props
17
+ }: DialogPrimitive.DialogPortalProps) => (
18
+ <DialogPrimitive.Portal className={cn(className)} {...props}>
19
+ <div className="fixed inset-0 z-50 flex items-start justify-center sm:items-center">
20
+ {children}
21
+ </div>
22
+ </DialogPrimitive.Portal>
23
+ )
24
+ DialogPortal.displayName = DialogPrimitive.Portal.displayName
25
+
26
+ const DialogOverlay = React.forwardRef<
27
+ React.ElementRef<typeof DialogPrimitive.Overlay>,
28
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
29
+ >(({ className, ...props }, ref) => (
30
+ <DialogPrimitive.Overlay
31
+ ref={ref}
32
+ className={cn(
33
+ 'fixed inset-0 z-50 bg-background/80 backdrop-blur-sm transition-all duration-100 data-[state=closed]:animate-out data-[state=closed]:fade-out data-[state=open]:fade-in',
34
+ className
35
+ )}
36
+ {...props}
37
+ />
38
+ ))
39
+ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
40
+
41
+ const DialogContent = React.forwardRef<
42
+ React.ElementRef<typeof DialogPrimitive.Content>,
43
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
44
+ >(({ className, children, ...props }, ref) => (
45
+ <DialogPortal>
46
+ <DialogOverlay />
47
+ <DialogPrimitive.Content
48
+ ref={ref}
49
+ className={cn(
50
+ 'fixed z-50 grid w-full gap-4 rounded-b-lg border bg-background p-6 shadow-sm animate-in data-[state=open]:fade-in-90 data-[state=open]:slide-in-from-bottom-10 sm:max-w-lg sm:rounded-lg sm:zoom-in-90 data-[state=open]:sm:slide-in-from-bottom-0',
51
+ className
52
+ )}
53
+ {...props}
54
+ >
55
+ {children}
56
+ <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
57
+ <IconClose />
58
+ <span className="sr-only">Close</span>
59
+ </DialogPrimitive.Close>
60
+ </DialogPrimitive.Content>
61
+ </DialogPortal>
62
+ ))
63
+ DialogContent.displayName = DialogPrimitive.Content.displayName
64
+
65
+ const DialogHeader = ({
66
+ className,
67
+ ...props
68
+ }: React.HTMLAttributes<HTMLDivElement>) => (
69
+ <div
70
+ className={cn(
71
+ 'flex flex-col space-y-1.5 text-center sm:text-left',
72
+ className
73
+ )}
74
+ {...props}
75
+ />
76
+ )
77
+ DialogHeader.displayName = 'DialogHeader'
78
+
79
+ const DialogFooter = ({
80
+ className,
81
+ ...props
82
+ }: React.HTMLAttributes<HTMLDivElement>) => (
83
+ <div
84
+ className={cn(
85
+ 'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
86
+ className
87
+ )}
88
+ {...props}
89
+ />
90
+ )
91
+ DialogFooter.displayName = 'DialogFooter'
92
+
93
+ const DialogTitle = React.forwardRef<
94
+ React.ElementRef<typeof DialogPrimitive.Title>,
95
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
96
+ >(({ className, ...props }, ref) => (
97
+ <DialogPrimitive.Title
98
+ ref={ref}
99
+ className={cn(
100
+ 'text-lg font-semibold leading-none tracking-tight',
101
+ className
102
+ )}
103
+ {...props}
104
+ />
105
+ ))
106
+ DialogTitle.displayName = DialogPrimitive.Title.displayName
107
+
108
+ const DialogDescription = React.forwardRef<
109
+ React.ElementRef<typeof DialogPrimitive.Description>,
110
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
111
+ >(({ className, ...props }, ref) => (
112
+ <DialogPrimitive.Description
113
+ ref={ref}
114
+ className={cn('text-sm text-muted-foreground', className)}
115
+ {...props}
116
+ />
117
+ ))
118
+ DialogDescription.displayName = DialogPrimitive.Description.displayName
119
+
120
+ export {
121
+ Dialog,
122
+ DialogTrigger,
123
+ DialogContent,
124
+ DialogHeader,
125
+ DialogFooter,
126
+ DialogTitle,
127
+ DialogDescription
128
+ }
@@ -0,0 +1,128 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'
5
+
6
+ import { cn } from '../../../lib/utils'
7
+
8
+ const DropdownMenu = DropdownMenuPrimitive.Root
9
+
10
+ const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
11
+
12
+ const DropdownMenuGroup = DropdownMenuPrimitive.Group
13
+
14
+ const DropdownMenuPortal = DropdownMenuPrimitive.Portal
15
+
16
+ const DropdownMenuSub = DropdownMenuPrimitive.Sub
17
+
18
+ const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
19
+
20
+ const DropdownMenuSubContent = React.forwardRef<
21
+ React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
22
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
23
+ >(({ className, ...props }, ref) => (
24
+ <DropdownMenuPrimitive.SubContent
25
+ ref={ref}
26
+ className={cn(
27
+ 'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md animate-in data-[side=bottom]:slide-in-from-top-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 data-[side=top]:slide-in-from-bottom-1',
28
+ className
29
+ )}
30
+ {...props}
31
+ />
32
+ ))
33
+ DropdownMenuSubContent.displayName =
34
+ DropdownMenuPrimitive.SubContent.displayName
35
+
36
+ const DropdownMenuContent = React.forwardRef<
37
+ React.ElementRef<typeof DropdownMenuPrimitive.Content>,
38
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
39
+ >(({ className, sideOffset = 4, ...props }, ref) => (
40
+ <DropdownMenuPrimitive.Portal>
41
+ <DropdownMenuPrimitive.Content
42
+ ref={ref}
43
+ sideOffset={sideOffset}
44
+ className={cn(
45
+ 'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow animate-in data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
46
+ className
47
+ )}
48
+ {...props}
49
+ />
50
+ </DropdownMenuPrimitive.Portal>
51
+ ))
52
+ DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
53
+
54
+ const DropdownMenuItem = React.forwardRef<
55
+ React.ElementRef<typeof DropdownMenuPrimitive.Item>,
56
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
57
+ inset?: boolean
58
+ }
59
+ >(({ className, inset, ...props }, ref) => (
60
+ <DropdownMenuPrimitive.Item
61
+ ref={ref}
62
+ className={cn(
63
+ 'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
64
+ inset && 'pl-8',
65
+ className
66
+ )}
67
+ {...props}
68
+ />
69
+ ))
70
+ DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
71
+
72
+ const DropdownMenuLabel = React.forwardRef<
73
+ React.ElementRef<typeof DropdownMenuPrimitive.Label>,
74
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
75
+ inset?: boolean
76
+ }
77
+ >(({ className, inset, ...props }, ref) => (
78
+ <DropdownMenuPrimitive.Label
79
+ ref={ref}
80
+ className={cn(
81
+ 'px-2 py-1.5 text-sm font-semibold',
82
+ inset && 'pl-8',
83
+ className
84
+ )}
85
+ {...props}
86
+ />
87
+ ))
88
+ DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
89
+
90
+ const DropdownMenuSeparator = React.forwardRef<
91
+ React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
92
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
93
+ >(({ className, ...props }, ref) => (
94
+ <DropdownMenuPrimitive.Separator
95
+ ref={ref}
96
+ className={cn('-mx-1 my-1 h-px bg-muted', className)}
97
+ {...props}
98
+ />
99
+ ))
100
+ DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
101
+
102
+ const DropdownMenuShortcut = ({
103
+ className,
104
+ ...props
105
+ }: React.HTMLAttributes<HTMLSpanElement>) => {
106
+ return (
107
+ <span
108
+ className={cn('ml-auto text-xs tracking-widest opacity-60', className)}
109
+ {...props}
110
+ />
111
+ )
112
+ }
113
+ DropdownMenuShortcut.displayName = 'DropdownMenuShortcut'
114
+
115
+ export {
116
+ DropdownMenu,
117
+ DropdownMenuTrigger,
118
+ DropdownMenuContent,
119
+ DropdownMenuItem,
120
+ DropdownMenuLabel,
121
+ DropdownMenuSeparator,
122
+ DropdownMenuShortcut,
123
+ DropdownMenuGroup,
124
+ DropdownMenuPortal,
125
+ DropdownMenuSub,
126
+ DropdownMenuSubContent,
127
+ DropdownMenuRadioGroup
128
+ }