@gram-ai/elements 1.25.2 → 1.26.1

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 (162) hide show
  1. package/dist/components/Chat/stories/Charts.stories.d.ts +37 -0
  2. package/dist/components/Chat/stories/GenerativeUI.stories.d.ts +17 -0
  3. package/dist/components/ui/button.d.ts +1 -1
  4. package/dist/components/ui/buttonVariants.d.ts +1 -1
  5. package/dist/components/ui/charts.stories.d.ts +43 -0
  6. package/dist/components/ui/generative-ui.stories.d.ts +53 -0
  7. package/dist/components/ui/tool-ui.d.ts +16 -1
  8. package/dist/elements.cjs +1 -1
  9. package/dist/elements.css +1 -1
  10. package/dist/elements.js +6 -6
  11. package/dist/index-BpJstUh1.cjs +280 -0
  12. package/dist/index-BpJstUh1.cjs.map +1 -0
  13. package/dist/index-CUitXazZ.js +30426 -0
  14. package/dist/index-CUitXazZ.js.map +1 -0
  15. package/dist/index-DdrZQXwQ.cjs +147 -0
  16. package/dist/index-DdrZQXwQ.cjs.map +1 -0
  17. package/dist/index-DfqYP0CD.js +37062 -0
  18. package/dist/index-DfqYP0CD.js.map +1 -0
  19. package/dist/plugins/chart/catalog.d.ts +123 -0
  20. package/dist/plugins/chart/index.d.ts +1 -1
  21. package/dist/plugins/chart/ui/area-chart.d.ts +16 -0
  22. package/dist/plugins/chart/ui/bar-chart.d.ts +16 -0
  23. package/dist/plugins/chart/ui/donut-chart.d.ts +17 -0
  24. package/dist/plugins/chart/ui/index.d.ts +7 -0
  25. package/dist/plugins/chart/ui/line-chart.d.ts +17 -0
  26. package/dist/plugins/chart/ui/pie-chart.d.ts +15 -0
  27. package/dist/plugins/chart/ui/radar-chart.d.ts +14 -0
  28. package/dist/plugins/chart/ui/scatter-chart.d.ts +18 -0
  29. package/dist/plugins/components/MacOSWindowFrame.d.ts +13 -0
  30. package/dist/plugins/components/PluginLoadingState.d.ts +1 -1
  31. package/dist/plugins/generative-ui/catalog.d.ts +293 -0
  32. package/dist/plugins/generative-ui/ui/accordion-wrapper.d.ts +18 -0
  33. package/dist/plugins/generative-ui/ui/accordion.d.ts +7 -0
  34. package/dist/plugins/generative-ui/ui/action-button.d.ts +10 -0
  35. package/dist/plugins/generative-ui/ui/alert-wrapper.d.ts +9 -0
  36. package/dist/plugins/generative-ui/ui/alert.d.ts +9 -0
  37. package/dist/plugins/generative-ui/ui/avatar-wrapper.d.ts +9 -0
  38. package/dist/plugins/generative-ui/ui/avatar.d.ts +11 -0
  39. package/dist/plugins/generative-ui/ui/badge.d.ts +12 -0
  40. package/dist/plugins/generative-ui/ui/button-wrapper.d.ts +15 -0
  41. package/dist/plugins/generative-ui/ui/button.d.ts +10 -0
  42. package/dist/plugins/generative-ui/ui/card-wrapper.d.ts +10 -0
  43. package/dist/plugins/generative-ui/ui/card.d.ts +9 -0
  44. package/dist/plugins/generative-ui/ui/checkbox-wrapper.d.ts +10 -0
  45. package/dist/plugins/generative-ui/ui/checkbox.d.ts +4 -0
  46. package/dist/plugins/generative-ui/ui/data-table.d.ts +10 -0
  47. package/dist/plugins/generative-ui/ui/dialog.d.ts +17 -0
  48. package/dist/plugins/generative-ui/ui/dropdown-menu.d.ts +25 -0
  49. package/dist/plugins/generative-ui/ui/grid.d.ts +6 -0
  50. package/dist/plugins/generative-ui/ui/index.d.ts +40 -0
  51. package/dist/plugins/generative-ui/ui/input-wrapper.d.ts +11 -0
  52. package/dist/plugins/generative-ui/ui/input.d.ts +3 -0
  53. package/dist/plugins/generative-ui/ui/label.d.ts +4 -0
  54. package/dist/plugins/generative-ui/ui/list.d.ts +6 -0
  55. package/dist/plugins/generative-ui/ui/metric.d.ts +7 -0
  56. package/dist/plugins/generative-ui/ui/pagination.d.ts +13 -0
  57. package/dist/plugins/generative-ui/ui/popover.d.ts +10 -0
  58. package/dist/plugins/generative-ui/ui/progress.d.ts +10 -0
  59. package/dist/plugins/generative-ui/ui/radio-group.d.ts +5 -0
  60. package/dist/plugins/generative-ui/ui/select-wrapper.d.ts +13 -0
  61. package/dist/plugins/generative-ui/ui/select.d.ts +15 -0
  62. package/dist/plugins/generative-ui/ui/separator.d.ts +4 -0
  63. package/dist/plugins/generative-ui/ui/skeleton-wrapper.d.ts +9 -0
  64. package/dist/plugins/generative-ui/ui/skeleton.d.ts +2 -0
  65. package/dist/plugins/generative-ui/ui/stack.d.ts +8 -0
  66. package/dist/plugins/generative-ui/ui/switch.d.ts +6 -0
  67. package/dist/plugins/generative-ui/ui/table.d.ts +10 -0
  68. package/dist/plugins/generative-ui/ui/tabs-wrapper.d.ts +21 -0
  69. package/dist/plugins/generative-ui/ui/tabs.d.ts +11 -0
  70. package/dist/plugins/generative-ui/ui/text.d.ts +7 -0
  71. package/dist/plugins/generative-ui/ui/textarea.d.ts +3 -0
  72. package/dist/plugins/generative-ui/ui/tooltip.d.ts +7 -0
  73. package/dist/plugins.cjs +1 -1
  74. package/dist/plugins.js +1 -1
  75. package/dist/{profiler-BaG0scxd.js → profiler-WoFj2UH8.js} +2 -2
  76. package/dist/{profiler-BaG0scxd.js.map → profiler-WoFj2UH8.js.map} +1 -1
  77. package/dist/{profiler-CuqENACf.cjs → profiler-ZLr2-8s7.cjs} +2 -2
  78. package/dist/{profiler-CuqENACf.cjs.map → profiler-ZLr2-8s7.cjs.map} +1 -1
  79. package/dist/{startRecording-BiLmoqZa.cjs → startRecording-BGnWDInp.cjs} +2 -2
  80. package/dist/{startRecording-BiLmoqZa.cjs.map → startRecording-BGnWDInp.cjs.map} +1 -1
  81. package/dist/{startRecording-86bHmd-l.js → startRecording-DzQo16WK.js} +2 -2
  82. package/dist/{startRecording-86bHmd-l.js.map → startRecording-DzQo16WK.js.map} +1 -1
  83. package/package.json +4 -1
  84. package/src/components/Chat/stories/Charts.stories.tsx +260 -0
  85. package/src/components/Chat/stories/ConnectionConfiguration.stories.tsx +6 -6
  86. package/src/components/Chat/stories/GenerativeUI.stories.tsx +113 -0
  87. package/src/components/Replay.stories.tsx +1 -1
  88. package/src/components/Replay.tsx +18 -13
  89. package/src/components/ui/charts.stories.tsx +246 -0
  90. package/src/components/ui/generative-ui.stories.tsx +557 -0
  91. package/src/components/ui/generative-ui.tsx +60 -360
  92. package/src/components/ui/tool-ui.stories.tsx +6 -3
  93. package/src/components/ui/tool-ui.tsx +31 -2
  94. package/src/hooks/useAuth.ts +17 -1
  95. package/src/hooks/useFollowOnSuggestions.ts +6 -1
  96. package/src/plugins/chart/catalog.ts +141 -0
  97. package/src/plugins/chart/component.tsx +79 -125
  98. package/src/plugins/chart/index.ts +141 -89
  99. package/src/plugins/chart/ui/area-chart.tsx +133 -0
  100. package/src/plugins/chart/ui/bar-chart.tsx +137 -0
  101. package/src/plugins/chart/ui/donut-chart.tsx +167 -0
  102. package/src/plugins/chart/ui/index.ts +7 -0
  103. package/src/plugins/chart/ui/line-chart.tsx +135 -0
  104. package/src/plugins/chart/ui/pie-chart.tsx +148 -0
  105. package/src/plugins/chart/ui/radar-chart.tsx +105 -0
  106. package/src/plugins/chart/ui/scatter-chart.tsx +132 -0
  107. package/src/plugins/components/MacOSWindowFrame.tsx +55 -0
  108. package/src/plugins/components/PluginLoadingState.tsx +9 -13
  109. package/src/plugins/generative-ui/catalog.ts +277 -0
  110. package/src/plugins/generative-ui/component.tsx +112 -21
  111. package/src/plugins/generative-ui/index.ts +20 -141
  112. package/src/plugins/generative-ui/ui/accordion-wrapper.tsx +57 -0
  113. package/src/plugins/generative-ui/ui/accordion.tsx +66 -0
  114. package/src/plugins/generative-ui/ui/action-button.tsx +68 -0
  115. package/src/plugins/generative-ui/ui/alert-wrapper.tsx +26 -0
  116. package/src/plugins/generative-ui/ui/alert.tsx +66 -0
  117. package/src/plugins/generative-ui/ui/avatar-wrapper.tsx +22 -0
  118. package/src/plugins/generative-ui/ui/avatar.tsx +109 -0
  119. package/src/plugins/generative-ui/ui/badge.tsx +65 -0
  120. package/src/plugins/generative-ui/ui/button-wrapper.tsx +32 -0
  121. package/src/plugins/generative-ui/ui/button.tsx +65 -0
  122. package/src/plugins/generative-ui/ui/card-wrapper.tsx +36 -0
  123. package/src/plugins/generative-ui/ui/card.tsx +92 -0
  124. package/src/plugins/generative-ui/ui/checkbox-wrapper.tsx +39 -0
  125. package/src/plugins/generative-ui/ui/checkbox.tsx +32 -0
  126. package/src/plugins/generative-ui/ui/data-table.tsx +53 -0
  127. package/src/plugins/generative-ui/ui/dialog.tsx +158 -0
  128. package/src/plugins/generative-ui/ui/dropdown-menu.tsx +257 -0
  129. package/src/plugins/generative-ui/ui/grid.tsx +29 -0
  130. package/src/plugins/generative-ui/ui/index.ts +43 -0
  131. package/src/plugins/generative-ui/ui/input-wrapper.tsx +38 -0
  132. package/src/plugins/generative-ui/ui/input.tsx +21 -0
  133. package/src/plugins/generative-ui/ui/label.tsx +24 -0
  134. package/src/plugins/generative-ui/ui/list.tsx +34 -0
  135. package/src/plugins/generative-ui/ui/metric.tsx +53 -0
  136. package/src/plugins/generative-ui/ui/pagination.tsx +127 -0
  137. package/src/plugins/generative-ui/ui/popover.tsx +89 -0
  138. package/src/plugins/generative-ui/ui/progress.tsx +57 -0
  139. package/src/plugins/generative-ui/ui/radio-group.tsx +45 -0
  140. package/src/plugins/generative-ui/ui/select-wrapper.tsx +41 -0
  141. package/src/plugins/generative-ui/ui/select.tsx +190 -0
  142. package/src/plugins/generative-ui/ui/separator.tsx +28 -0
  143. package/src/plugins/generative-ui/ui/skeleton-wrapper.tsx +30 -0
  144. package/src/plugins/generative-ui/ui/skeleton.tsx +13 -0
  145. package/src/plugins/generative-ui/ui/stack.tsx +54 -0
  146. package/src/plugins/generative-ui/ui/switch.tsx +35 -0
  147. package/src/plugins/generative-ui/ui/table.tsx +116 -0
  148. package/src/plugins/generative-ui/ui/tabs-wrapper.tsx +51 -0
  149. package/src/plugins/generative-ui/ui/tabs.tsx +92 -0
  150. package/src/plugins/generative-ui/ui/text.tsx +33 -0
  151. package/src/plugins/generative-ui/ui/textarea.tsx +18 -0
  152. package/src/plugins/generative-ui/ui/tooltip.tsx +57 -0
  153. package/dist/components/Chat/stories/Plugins.stories.d.ts +0 -12
  154. package/dist/index-B8nSCdu4.cjs +0 -251
  155. package/dist/index-B8nSCdu4.cjs.map +0 -1
  156. package/dist/index-CAtaLV1E.cjs +0 -187
  157. package/dist/index-CAtaLV1E.cjs.map +0 -1
  158. package/dist/index-CJrwma08.js +0 -27232
  159. package/dist/index-CJrwma08.js.map +0 -1
  160. package/dist/index-DLWQ91ow.js +0 -40049
  161. package/dist/index-DLWQ91ow.js.map +0 -1
  162. package/src/components/Chat/stories/Plugins.stories.tsx +0 -158
@@ -0,0 +1,66 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { ChevronDownIcon } from 'lucide-react'
5
+ import { Accordion as AccordionPrimitive } from 'radix-ui'
6
+
7
+ import { cn } from '@/lib/utils'
8
+
9
+ function Accordion({
10
+ ...props
11
+ }: React.ComponentProps<typeof AccordionPrimitive.Root>) {
12
+ return <AccordionPrimitive.Root data-slot="accordion" {...props} />
13
+ }
14
+
15
+ function AccordionItem({
16
+ className,
17
+ ...props
18
+ }: React.ComponentProps<typeof AccordionPrimitive.Item>) {
19
+ return (
20
+ <AccordionPrimitive.Item
21
+ data-slot="accordion-item"
22
+ className={cn('border-b last:border-b-0', className)}
23
+ {...props}
24
+ />
25
+ )
26
+ }
27
+
28
+ function AccordionTrigger({
29
+ className,
30
+ children,
31
+ ...props
32
+ }: React.ComponentProps<typeof AccordionPrimitive.Trigger>) {
33
+ return (
34
+ <AccordionPrimitive.Header className="flex">
35
+ <AccordionPrimitive.Trigger
36
+ data-slot="accordion-trigger"
37
+ className={cn(
38
+ 'text-foreground focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180',
39
+ className
40
+ )}
41
+ {...props}
42
+ >
43
+ {children}
44
+ <ChevronDownIcon className="text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200" />
45
+ </AccordionPrimitive.Trigger>
46
+ </AccordionPrimitive.Header>
47
+ )
48
+ }
49
+
50
+ function AccordionContent({
51
+ className,
52
+ children,
53
+ ...props
54
+ }: React.ComponentProps<typeof AccordionPrimitive.Content>) {
55
+ return (
56
+ <AccordionPrimitive.Content
57
+ data-slot="accordion-content"
58
+ className="data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm"
59
+ {...props}
60
+ >
61
+ <div className={cn('pt-0 pb-4', className)}>{children}</div>
62
+ </AccordionPrimitive.Content>
63
+ )
64
+ }
65
+
66
+ export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
@@ -0,0 +1,68 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { Button, buttonVariants } from './button'
5
+ import type { VariantProps } from 'class-variance-authority'
6
+ import { cn } from '@/lib/utils'
7
+ import { useToolExecution } from '@/contexts/ToolExecutionContext'
8
+
9
+ export interface ActionButtonProps
10
+ extends
11
+ Omit<React.ComponentProps<'button'>, 'onClick'>,
12
+ VariantProps<typeof buttonVariants> {
13
+ label: string
14
+ /** Tool name to invoke when clicked (matches LLM prompt) */
15
+ action: string
16
+ args?: Record<string, unknown>
17
+ }
18
+
19
+ export function ActionButton({
20
+ label,
21
+ action,
22
+ args,
23
+ variant = 'default',
24
+ size = 'default',
25
+ className,
26
+ disabled,
27
+ ...props
28
+ }: ActionButtonProps) {
29
+ const { executeTool, isToolAvailable } = useToolExecution()
30
+ const [isLoading, setIsLoading] = React.useState(false)
31
+
32
+ const toolAvailable = isToolAvailable(action)
33
+
34
+ const [error, setError] = React.useState<string | null>(null)
35
+
36
+ const handleClick = React.useCallback(async () => {
37
+ if (!toolAvailable || isLoading) return
38
+
39
+ setIsLoading(true)
40
+ setError(null)
41
+ try {
42
+ const result = await executeTool(action, args ?? {})
43
+ if (!result.success && result.error) {
44
+ setError(result.error)
45
+ }
46
+ } catch (err) {
47
+ setError(err instanceof Error ? err.message : 'Unknown error')
48
+ } finally {
49
+ setIsLoading(false)
50
+ }
51
+ }, [action, args, executeTool, isLoading, toolAvailable])
52
+
53
+ return (
54
+ <div className="inline-flex flex-col gap-1">
55
+ <Button
56
+ variant={error ? 'destructive' : variant}
57
+ size={size}
58
+ className={cn(className)}
59
+ onClick={handleClick}
60
+ disabled={disabled || isLoading || !toolAvailable}
61
+ {...props}
62
+ >
63
+ {isLoading ? 'Loading...' : label}
64
+ </Button>
65
+ {error && <span className="text-destructive text-xs">{error}</span>}
66
+ </div>
67
+ )
68
+ }
@@ -0,0 +1,26 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { Alert, AlertTitle, AlertDescription } from './alert'
5
+
6
+ export interface AlertWrapperProps {
7
+ title: string
8
+ description?: string
9
+ variant?: 'default' | 'destructive'
10
+ }
11
+
12
+ /**
13
+ * Alert wrapper that takes title and description as props.
14
+ */
15
+ export function AlertWrapper({
16
+ title,
17
+ description,
18
+ variant = 'default',
19
+ }: AlertWrapperProps) {
20
+ return (
21
+ <Alert variant={variant}>
22
+ <AlertTitle>{title}</AlertTitle>
23
+ {description && <AlertDescription>{description}</AlertDescription>}
24
+ </Alert>
25
+ )
26
+ }
@@ -0,0 +1,66 @@
1
+ import * as React from 'react'
2
+ import { cva, type VariantProps } from 'class-variance-authority'
3
+
4
+ import { cn } from '@/lib/utils'
5
+
6
+ const alertVariants = cva(
7
+ 'relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current',
8
+ {
9
+ variants: {
10
+ variant: {
11
+ default: 'bg-card text-card-foreground',
12
+ destructive:
13
+ 'text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90',
14
+ },
15
+ },
16
+ defaultVariants: {
17
+ variant: 'default',
18
+ },
19
+ }
20
+ )
21
+
22
+ function Alert({
23
+ className,
24
+ variant,
25
+ ...props
26
+ }: React.ComponentProps<'div'> & VariantProps<typeof alertVariants>) {
27
+ return (
28
+ <div
29
+ data-slot="alert"
30
+ role="alert"
31
+ className={cn(alertVariants({ variant }), className)}
32
+ {...props}
33
+ />
34
+ )
35
+ }
36
+
37
+ function AlertTitle({ className, ...props }: React.ComponentProps<'div'>) {
38
+ return (
39
+ <div
40
+ data-slot="alert-title"
41
+ className={cn(
42
+ 'col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight',
43
+ className
44
+ )}
45
+ {...props}
46
+ />
47
+ )
48
+ }
49
+
50
+ function AlertDescription({
51
+ className,
52
+ ...props
53
+ }: React.ComponentProps<'div'>) {
54
+ return (
55
+ <div
56
+ data-slot="alert-description"
57
+ className={cn(
58
+ 'text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed',
59
+ className
60
+ )}
61
+ {...props}
62
+ />
63
+ )
64
+ }
65
+
66
+ export { Alert, AlertTitle, AlertDescription }
@@ -0,0 +1,22 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { Avatar, AvatarImage, AvatarFallback } from './avatar'
5
+
6
+ export interface AvatarWrapperProps {
7
+ src?: string
8
+ alt?: string
9
+ fallback: string
10
+ }
11
+
12
+ /**
13
+ * Avatar wrapper that takes src, alt, and fallback as props.
14
+ */
15
+ export function AvatarWrapper({ src, alt, fallback }: AvatarWrapperProps) {
16
+ return (
17
+ <Avatar>
18
+ {src && <AvatarImage src={src} alt={alt} />}
19
+ <AvatarFallback>{fallback}</AvatarFallback>
20
+ </Avatar>
21
+ )
22
+ }
@@ -0,0 +1,109 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { Avatar as AvatarPrimitive } from 'radix-ui'
5
+
6
+ import { cn } from '@/lib/utils'
7
+
8
+ function Avatar({
9
+ className,
10
+ size = 'default',
11
+ ...props
12
+ }: React.ComponentProps<typeof AvatarPrimitive.Root> & {
13
+ size?: 'default' | 'sm' | 'lg'
14
+ }) {
15
+ return (
16
+ <AvatarPrimitive.Root
17
+ data-slot="avatar"
18
+ data-size={size}
19
+ className={cn(
20
+ 'group/avatar relative flex size-8 shrink-0 overflow-hidden rounded-full select-none data-[size=lg]:size-10 data-[size=sm]:size-6',
21
+ className
22
+ )}
23
+ {...props}
24
+ />
25
+ )
26
+ }
27
+
28
+ function AvatarImage({
29
+ className,
30
+ ...props
31
+ }: React.ComponentProps<typeof AvatarPrimitive.Image>) {
32
+ return (
33
+ <AvatarPrimitive.Image
34
+ data-slot="avatar-image"
35
+ className={cn('aspect-square size-full', className)}
36
+ {...props}
37
+ />
38
+ )
39
+ }
40
+
41
+ function AvatarFallback({
42
+ className,
43
+ ...props
44
+ }: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
45
+ return (
46
+ <AvatarPrimitive.Fallback
47
+ data-slot="avatar-fallback"
48
+ className={cn(
49
+ 'bg-muted text-muted-foreground flex size-full items-center justify-center rounded-full text-sm group-data-[size=sm]/avatar:text-xs',
50
+ className
51
+ )}
52
+ {...props}
53
+ />
54
+ )
55
+ }
56
+
57
+ function AvatarBadge({ className, ...props }: React.ComponentProps<'span'>) {
58
+ return (
59
+ <span
60
+ data-slot="avatar-badge"
61
+ className={cn(
62
+ 'bg-primary text-primary-foreground ring-background absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full ring-2 select-none',
63
+ 'group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden',
64
+ 'group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2',
65
+ 'group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2',
66
+ className
67
+ )}
68
+ {...props}
69
+ />
70
+ )
71
+ }
72
+
73
+ function AvatarGroup({ className, ...props }: React.ComponentProps<'div'>) {
74
+ return (
75
+ <div
76
+ data-slot="avatar-group"
77
+ className={cn(
78
+ '*:data-[slot=avatar]:ring-background group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2',
79
+ className
80
+ )}
81
+ {...props}
82
+ />
83
+ )
84
+ }
85
+
86
+ function AvatarGroupCount({
87
+ className,
88
+ ...props
89
+ }: React.ComponentProps<'div'>) {
90
+ return (
91
+ <div
92
+ data-slot="avatar-group-count"
93
+ className={cn(
94
+ 'bg-muted text-muted-foreground ring-background relative flex size-8 shrink-0 items-center justify-center rounded-full text-sm ring-2 group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3',
95
+ className
96
+ )}
97
+ {...props}
98
+ />
99
+ )
100
+ }
101
+
102
+ export {
103
+ Avatar,
104
+ AvatarImage,
105
+ AvatarFallback,
106
+ AvatarBadge,
107
+ AvatarGroup,
108
+ AvatarGroupCount,
109
+ }
@@ -0,0 +1,65 @@
1
+ import * as React from 'react'
2
+ import { cva, type VariantProps } from 'class-variance-authority'
3
+ import { Slot } from 'radix-ui'
4
+
5
+ import { cn } from '@/lib/utils'
6
+
7
+ const badgeVariants = cva(
8
+ 'inline-flex items-center justify-center rounded-full border border-transparent px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-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 transition-[color,box-shadow] overflow-hidden',
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default: 'bg-primary text-primary-foreground [a&]:hover:bg-primary/90',
13
+ secondary:
14
+ 'bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90',
15
+ /** Matches LLM prompt variant */
16
+ success:
17
+ 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-100',
18
+ /** Matches LLM prompt variant */
19
+ warning:
20
+ 'bg-amber-100 text-amber-800 dark:bg-amber-900 dark:text-amber-100',
21
+ /** Matches LLM prompt variant */
22
+ error: 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-100',
23
+ destructive:
24
+ 'bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
25
+ outline:
26
+ 'border-border text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground',
27
+ },
28
+ },
29
+ defaultVariants: {
30
+ variant: 'default',
31
+ },
32
+ }
33
+ )
34
+
35
+ interface BadgeProps
36
+ extends React.ComponentProps<'span'>, VariantProps<typeof badgeVariants> {
37
+ asChild?: boolean
38
+ /** Content text (matches LLM prompt) - rendered as children */
39
+ content?: string
40
+ }
41
+
42
+ function Badge({
43
+ className,
44
+ variant = 'default',
45
+ asChild = false,
46
+ content,
47
+ children,
48
+ ...props
49
+ }: BadgeProps) {
50
+ const Comp = asChild ? Slot.Root : 'span'
51
+
52
+ return (
53
+ <Comp
54
+ data-slot="badge"
55
+ data-variant={variant}
56
+ className={cn(badgeVariants({ variant }), className)}
57
+ {...props}
58
+ >
59
+ {content ?? children}
60
+ </Comp>
61
+ )
62
+ }
63
+
64
+ // eslint-disable-next-line react-refresh/only-export-components
65
+ export { Badge, badgeVariants }
@@ -0,0 +1,32 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { Button } from './button'
5
+
6
+ export interface ButtonWrapperProps {
7
+ label: string
8
+ variant?: 'default' | 'secondary' | 'destructive' | 'outline' | 'ghost'
9
+ size?: 'default' | 'sm' | 'lg' | 'icon'
10
+ disabled?: boolean
11
+ /** Backend action to trigger (future use) */
12
+ action?: string
13
+ /** Parameters for the action (future use) */
14
+ actionParams?: Record<string, unknown>
15
+ }
16
+
17
+ /**
18
+ * Button wrapper that takes label as a prop.
19
+ * The action/actionParams props are for future backend integration.
20
+ */
21
+ export function ButtonWrapper({
22
+ label,
23
+ variant = 'default',
24
+ size = 'default',
25
+ disabled = false,
26
+ }: ButtonWrapperProps) {
27
+ return (
28
+ <Button variant={variant} size={size} disabled={disabled}>
29
+ {label}
30
+ </Button>
31
+ )
32
+ }
@@ -0,0 +1,65 @@
1
+ import * as React from 'react'
2
+ import { cva, type VariantProps } from 'class-variance-authority'
3
+ import { Slot } from 'radix-ui'
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: 'bg-primary text-primary-foreground hover:bg-primary/90',
13
+ destructive:
14
+ 'bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
15
+ outline:
16
+ 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',
17
+ secondary:
18
+ 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
19
+ ghost:
20
+ 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
21
+ link: 'text-primary underline-offset-4 hover:underline',
22
+ },
23
+ size: {
24
+ default: 'h-9 px-4 py-2 has-[>svg]:px-3',
25
+ xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
26
+ sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5',
27
+ lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',
28
+ icon: 'size-9',
29
+ 'icon-xs': "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
30
+ 'icon-sm': 'size-8',
31
+ 'icon-lg': 'size-10',
32
+ },
33
+ },
34
+ defaultVariants: {
35
+ variant: 'default',
36
+ size: 'default',
37
+ },
38
+ }
39
+ )
40
+
41
+ function Button({
42
+ className,
43
+ variant = 'default',
44
+ size = 'default',
45
+ asChild = false,
46
+ ...props
47
+ }: React.ComponentProps<'button'> &
48
+ VariantProps<typeof buttonVariants> & {
49
+ asChild?: boolean
50
+ }) {
51
+ const Comp = asChild ? Slot.Root : 'button'
52
+
53
+ return (
54
+ <Comp
55
+ data-slot="button"
56
+ data-variant={variant}
57
+ data-size={size}
58
+ className={cn(buttonVariants({ variant, size, className }))}
59
+ {...props}
60
+ />
61
+ )
62
+ }
63
+
64
+ // eslint-disable-next-line react-refresh/only-export-components
65
+ export { Button, buttonVariants }
@@ -0,0 +1,36 @@
1
+ import * as React from 'react'
2
+ import { cn } from '@/lib/utils'
3
+
4
+ export interface CardWrapperProps extends React.ComponentProps<'div'> {
5
+ title?: string
6
+ }
7
+
8
+ /**
9
+ * CardWrapper is a frameless container for generative UI content.
10
+ * It has no border or shadow since it's rendered inside MacOSWindowFrame.
11
+ * Children are spaced using flex gap for proper composition.
12
+ */
13
+ export function CardWrapper({
14
+ title,
15
+ className,
16
+ children,
17
+ ...props
18
+ }: CardWrapperProps) {
19
+ return (
20
+ <div
21
+ data-slot="card-wrapper"
22
+ className={cn(
23
+ 'bg-card text-card-foreground flex flex-col gap-6 p-6',
24
+ className
25
+ )}
26
+ {...props}
27
+ >
28
+ {title && (
29
+ <div className="text-foreground text-lg leading-none font-semibold">
30
+ {title}
31
+ </div>
32
+ )}
33
+ <div className="flex flex-col gap-6">{children}</div>
34
+ </div>
35
+ )
36
+ }
@@ -0,0 +1,92 @@
1
+ import * as React from 'react'
2
+
3
+ import { cn } from '@/lib/utils'
4
+
5
+ function Card({ className, ...props }: React.ComponentProps<'div'>) {
6
+ 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
+ />
15
+ )
16
+ }
17
+
18
+ function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
19
+ return (
20
+ <div
21
+ data-slot="card-header"
22
+ className={cn(
23
+ '@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6',
24
+ className
25
+ )}
26
+ {...props}
27
+ />
28
+ )
29
+ }
30
+
31
+ function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
32
+ return (
33
+ <div
34
+ data-slot="card-title"
35
+ className={cn('leading-none font-semibold', className)}
36
+ {...props}
37
+ />
38
+ )
39
+ }
40
+
41
+ function CardDescription({ className, ...props }: React.ComponentProps<'div'>) {
42
+ return (
43
+ <div
44
+ data-slot="card-description"
45
+ className={cn('text-muted-foreground text-sm', className)}
46
+ {...props}
47
+ />
48
+ )
49
+ }
50
+
51
+ function CardAction({ className, ...props }: React.ComponentProps<'div'>) {
52
+ return (
53
+ <div
54
+ data-slot="card-action"
55
+ className={cn(
56
+ 'col-start-2 row-span-2 row-start-1 self-start justify-self-end',
57
+ className
58
+ )}
59
+ {...props}
60
+ />
61
+ )
62
+ }
63
+
64
+ function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
65
+ return (
66
+ <div
67
+ data-slot="card-content"
68
+ className={cn('px-6', className)}
69
+ {...props}
70
+ />
71
+ )
72
+ }
73
+
74
+ function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
75
+ return (
76
+ <div
77
+ data-slot="card-footer"
78
+ className={cn('flex items-center px-6 [.border-t]:pt-6', className)}
79
+ {...props}
80
+ />
81
+ )
82
+ }
83
+
84
+ export {
85
+ Card,
86
+ CardHeader,
87
+ CardFooter,
88
+ CardTitle,
89
+ CardAction,
90
+ CardDescription,
91
+ CardContent,
92
+ }
@@ -0,0 +1,39 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { Checkbox } from './checkbox'
5
+ import { Label } from './label'
6
+
7
+ export interface CheckboxWrapperProps {
8
+ label?: string
9
+ /** Path for form state management (future use) */
10
+ valuePath: string
11
+ defaultChecked?: boolean
12
+ }
13
+
14
+ /**
15
+ * Checkbox wrapper that adds label support.
16
+ */
17
+ export function CheckboxWrapper({
18
+ label,
19
+ valuePath,
20
+ defaultChecked,
21
+ }: CheckboxWrapperProps) {
22
+ const id = React.useId()
23
+
24
+ return (
25
+ <div className="flex items-center gap-2">
26
+ <Checkbox
27
+ id={id}
28
+ name={valuePath}
29
+ defaultChecked={defaultChecked}
30
+ data-value-path={valuePath}
31
+ />
32
+ {label && (
33
+ <Label htmlFor={id} className="cursor-pointer">
34
+ {label}
35
+ </Label>
36
+ )}
37
+ </div>
38
+ )
39
+ }