@elizaos/ui 2.0.0-alpha.73 → 2.0.0-alpha.76

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 (171) hide show
  1. package/components/ui/badge.d.ts +10 -0
  2. package/components/ui/badge.d.ts.map +1 -0
  3. package/components/ui/badge.js +20 -0
  4. package/components/ui/banner.d.ts +18 -0
  5. package/components/ui/banner.d.ts.map +1 -0
  6. package/components/ui/banner.js +27 -0
  7. package/components/ui/button.d.ts +12 -0
  8. package/components/ui/button.d.ts.map +1 -0
  9. package/components/ui/button.js +37 -0
  10. package/components/ui/card.d.ts +9 -0
  11. package/components/ui/card.d.ts.map +1 -0
  12. package/components/ui/card.js +16 -0
  13. package/components/ui/chat-atoms.d.ts +26 -0
  14. package/components/ui/chat-atoms.d.ts.map +1 -0
  15. package/components/ui/chat-atoms.js +17 -0
  16. package/components/ui/checkbox.d.ts +5 -0
  17. package/components/ui/checkbox.d.ts.map +1 -0
  18. package/components/ui/checkbox.js +8 -0
  19. package/components/ui/confirm-delete.d.ts +12 -0
  20. package/components/ui/confirm-delete.d.ts.map +1 -0
  21. package/components/ui/confirm-delete.js +13 -0
  22. package/components/ui/confirm-dialog.d.ts +24 -0
  23. package/components/ui/confirm-dialog.d.ts.map +1 -0
  24. package/components/ui/confirm-dialog.js +55 -0
  25. package/components/ui/connection-status.d.ts +9 -0
  26. package/components/ui/connection-status.d.ts.map +1 -0
  27. package/components/ui/connection-status.js +25 -0
  28. package/components/ui/copy-button.d.ts +13 -0
  29. package/components/ui/copy-button.d.ts.map +1 -0
  30. package/components/ui/copy-button.js +14 -0
  31. package/components/ui/dialog.d.ts +20 -0
  32. package/components/ui/dialog.d.ts.map +1 -0
  33. package/components/ui/dialog.js +22 -0
  34. package/components/ui/dropdown-menu.d.ts +28 -0
  35. package/components/ui/dropdown-menu.d.ts.map +1 -0
  36. package/components/ui/dropdown-menu.js +35 -0
  37. package/components/ui/empty-state.d.ts +13 -0
  38. package/components/ui/empty-state.d.ts.map +1 -0
  39. package/components/ui/empty-state.js +5 -0
  40. package/components/ui/error-boundary.d.ts +18 -0
  41. package/components/ui/error-boundary.d.ts.map +1 -0
  42. package/components/ui/error-boundary.js +27 -0
  43. package/components/ui/grid.d.ts +11 -0
  44. package/components/ui/grid.d.ts.map +1 -0
  45. package/components/ui/grid.js +30 -0
  46. package/components/ui/input.d.ts +6 -0
  47. package/components/ui/input.d.ts.map +1 -0
  48. package/components/ui/input.js +8 -0
  49. package/components/ui/label.d.ts +6 -0
  50. package/components/ui/label.d.ts.map +1 -0
  51. package/components/ui/label.js +9 -0
  52. package/components/ui/popover.d.ts +7 -0
  53. package/components/ui/popover.d.ts.map +1 -0
  54. package/components/ui/popover.js +9 -0
  55. package/components/ui/save-footer.d.ts +13 -0
  56. package/components/ui/save-footer.d.ts.map +1 -0
  57. package/components/ui/save-footer.js +9 -0
  58. package/components/ui/search-bar.d.ts +17 -0
  59. package/components/ui/search-bar.d.ts.map +1 -0
  60. package/components/ui/search-bar.js +19 -0
  61. package/components/ui/search-input.d.ts +11 -0
  62. package/components/ui/search-input.d.ts.map +1 -0
  63. package/components/ui/search-input.js +9 -0
  64. package/components/ui/section-card.d.ts +15 -0
  65. package/components/ui/section-card.d.ts.map +1 -0
  66. package/components/ui/section-card.js +9 -0
  67. package/components/ui/select.d.ts +14 -0
  68. package/components/ui/select.d.ts.map +1 -0
  69. package/components/ui/select.js +26 -0
  70. package/components/ui/separator.d.ts +5 -0
  71. package/components/ui/separator.d.ts.map +1 -0
  72. package/components/ui/separator.js +7 -0
  73. package/components/ui/skeleton.d.ts +17 -0
  74. package/components/ui/skeleton.d.ts.map +1 -0
  75. package/components/ui/skeleton.js +25 -0
  76. package/components/ui/slider.d.ts +5 -0
  77. package/components/ui/slider.d.ts.map +1 -0
  78. package/components/ui/slider.js +7 -0
  79. package/components/ui/sonner.d.ts +5 -0
  80. package/components/ui/sonner.d.ts.map +1 -0
  81. package/components/ui/sonner.js +15 -0
  82. package/components/ui/spinner.d.ts +6 -0
  83. package/components/ui/spinner.d.ts.map +1 -0
  84. package/components/ui/spinner.js +8 -0
  85. package/components/ui/stack.d.ts +13 -0
  86. package/components/ui/stack.d.ts.map +1 -0
  87. package/components/ui/stack.js +39 -0
  88. package/components/ui/status-badge.d.ts +20 -0
  89. package/components/ui/status-badge.d.ts.map +1 -0
  90. package/components/ui/status-badge.js +41 -0
  91. package/components/ui/switch.d.ts +5 -0
  92. package/components/ui/switch.d.ts.map +1 -0
  93. package/components/ui/switch.js +7 -0
  94. package/components/ui/tabs.d.ts +8 -0
  95. package/components/ui/tabs.d.ts.map +1 -0
  96. package/components/ui/tabs.js +12 -0
  97. package/components/ui/tag-editor.d.ts +24 -0
  98. package/components/ui/tag-editor.d.ts.map +1 -0
  99. package/components/ui/tag-editor.js +32 -0
  100. package/components/ui/tag-input.d.ts +19 -0
  101. package/components/ui/tag-input.d.ts.map +1 -0
  102. package/components/ui/tag-input.js +28 -0
  103. package/components/ui/textarea.d.ts +6 -0
  104. package/components/ui/textarea.d.ts.map +1 -0
  105. package/components/ui/textarea.js +8 -0
  106. package/components/ui/themed-select.d.ts +27 -0
  107. package/components/ui/themed-select.d.ts.map +1 -0
  108. package/components/ui/themed-select.js +57 -0
  109. package/components/ui/tooltip-extended.d.ts +76 -0
  110. package/components/ui/tooltip-extended.d.ts.map +1 -0
  111. package/components/ui/tooltip-extended.js +128 -0
  112. package/components/ui/tooltip.d.ts +8 -0
  113. package/components/ui/tooltip.d.ts.map +1 -0
  114. package/components/ui/tooltip.js +10 -0
  115. package/components/ui/typography.d.ts +17 -0
  116. package/components/ui/typography.d.ts.map +1 -0
  117. package/components/ui/typography.js +44 -0
  118. package/index.d.ts +42 -0
  119. package/index.d.ts.map +1 -0
  120. package/{src/index.ts → index.js} +0 -1
  121. package/lib/button-styles.d.ts +12 -0
  122. package/lib/button-styles.d.ts.map +1 -0
  123. package/lib/button-styles.js +11 -0
  124. package/lib/utils.d.ts +6 -0
  125. package/lib/utils.d.ts.map +1 -0
  126. package/{src/lib/utils.ts → lib/utils.js} +3 -4
  127. package/package.json +16 -18
  128. package/README.md +0 -6
  129. package/src/components/ui/badge.tsx +0 -35
  130. package/src/components/ui/banner.tsx +0 -81
  131. package/src/components/ui/button.tsx +0 -56
  132. package/src/components/ui/card.tsx +0 -79
  133. package/src/components/ui/chat-atoms.tsx +0 -129
  134. package/src/components/ui/checkbox.tsx +0 -28
  135. package/src/components/ui/confirm-delete.tsx +0 -67
  136. package/src/components/ui/confirm-dialog.tsx +0 -142
  137. package/src/components/ui/connection-status.tsx +0 -54
  138. package/src/components/ui/copy-button.tsx +0 -60
  139. package/src/components/ui/dialog.tsx +0 -120
  140. package/src/components/ui/dropdown-menu.tsx +0 -198
  141. package/src/components/ui/empty-state.tsx +0 -42
  142. package/src/components/ui/error-boundary.tsx +0 -63
  143. package/src/components/ui/grid.tsx +0 -43
  144. package/src/components/ui/input.tsx +0 -25
  145. package/src/components/ui/label.tsx +0 -24
  146. package/src/components/ui/popover.tsx +0 -29
  147. package/src/components/ui/save-footer.tsx +0 -58
  148. package/src/components/ui/search-bar.tsx +0 -61
  149. package/src/components/ui/search-input.tsx +0 -56
  150. package/src/components/ui/section-card.tsx +0 -85
  151. package/src/components/ui/select.tsx +0 -158
  152. package/src/components/ui/separator.tsx +0 -29
  153. package/src/components/ui/skeleton.tsx +0 -115
  154. package/src/components/ui/slider.tsx +0 -26
  155. package/src/components/ui/sonner.tsx +0 -28
  156. package/src/components/ui/spinner.tsx +0 -21
  157. package/src/components/ui/stack.tsx +0 -55
  158. package/src/components/ui/status-badge.tsx +0 -128
  159. package/src/components/ui/switch.tsx +0 -27
  160. package/src/components/ui/tabs.tsx +0 -53
  161. package/src/components/ui/tag-editor.tsx +0 -111
  162. package/src/components/ui/tag-input.tsx +0 -108
  163. package/src/components/ui/textarea.tsx +0 -24
  164. package/src/components/ui/themed-select.tsx +0 -141
  165. package/src/components/ui/tooltip-extended.tsx +0 -340
  166. package/src/components/ui/tooltip.tsx +0 -28
  167. package/src/components/ui/typography.tsx +0 -74
  168. package/src/lib/button-styles.ts +0 -19
  169. package/tsconfig.build.json +0 -18
  170. package/tsconfig.json +0 -32
  171. /package/{src/styles → styles}/theme.css +0 -0
@@ -1,26 +0,0 @@
1
- import * as SliderPrimitive from "@radix-ui/react-slider";
2
- import * as React from "react";
3
-
4
- import { cn } from "../../lib/utils";
5
-
6
- const Slider = React.forwardRef<
7
- React.ElementRef<typeof SliderPrimitive.Root>,
8
- React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>
9
- >(({ className, ...props }, ref) => (
10
- <SliderPrimitive.Root
11
- ref={ref}
12
- className={cn(
13
- "relative flex w-full touch-none select-none items-center",
14
- className,
15
- )}
16
- {...props}
17
- >
18
- <SliderPrimitive.Track className="relative h-2 w-full grow overflow-hidden rounded-full bg-secondary">
19
- <SliderPrimitive.Range className="absolute h-full bg-primary" />
20
- </SliderPrimitive.Track>
21
- <SliderPrimitive.Thumb className="block h-5 w-5 rounded-full border-2 border-primary bg-bg ring-offset-bg 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" />
22
- </SliderPrimitive.Root>
23
- ));
24
- Slider.displayName = SliderPrimitive.Root.displayName;
25
-
26
- export { Slider };
@@ -1,28 +0,0 @@
1
- import { useTheme } from "next-themes";
2
- import { Toaster as Sonner } from "sonner";
3
-
4
- type ToasterProps = React.ComponentProps<typeof Sonner>;
5
-
6
- const Toaster = ({ ...props }: ToasterProps) => {
7
- const { theme = "system" } = useTheme();
8
-
9
- return (
10
- <Sonner
11
- theme={theme as ToasterProps["theme"]}
12
- className="toaster group"
13
- toastOptions={{
14
- classNames: {
15
- toast:
16
- "group toast group-[.toaster]:bg-bg group-[.toaster]:text-txt group-[.toaster]:border-border group-[.toaster]:shadow-lg",
17
- description: "group-[.toast]:text-muted",
18
- actionButton:
19
- "group-[.toast]:bg-primary group-[.toast]:text-primary-fg",
20
- cancelButton: "group-[.toast]:bg-muted group-[.toast]:text-muted-fg",
21
- },
22
- }}
23
- {...props}
24
- />
25
- );
26
- };
27
-
28
- export { Toaster };
@@ -1,21 +0,0 @@
1
- import { Loader2 } from "lucide-react";
2
- import * as React from "react";
3
- import { cn } from "../../lib/utils";
4
-
5
- export interface SpinnerProps extends React.SVGAttributes<SVGSVGElement> {
6
- size?: number | string;
7
- }
8
-
9
- export const Spinner = React.forwardRef<SVGSVGElement, SpinnerProps>(
10
- ({ className, size = 24, ...props }, ref) => {
11
- return (
12
- <Loader2
13
- ref={ref}
14
- size={size}
15
- className={cn("animate-spin text-muted", className)}
16
- {...props}
17
- />
18
- );
19
- },
20
- );
21
- Spinner.displayName = "Spinner";
@@ -1,55 +0,0 @@
1
- import { cva, type VariantProps } from "class-variance-authority";
2
- import * as React from "react";
3
- import { cn } from "../../lib/utils";
4
-
5
- const stackVariants = cva("flex", {
6
- variants: {
7
- direction: {
8
- row: "flex-row",
9
- col: "flex-col",
10
- },
11
- align: {
12
- start: "items-start",
13
- center: "items-center",
14
- end: "items-end",
15
- stretch: "items-stretch",
16
- baseline: "items-baseline",
17
- },
18
- justify: {
19
- start: "justify-start",
20
- center: "justify-center",
21
- end: "justify-end",
22
- between: "justify-between",
23
- },
24
- spacing: {
25
- none: "gap-0",
26
- sm: "gap-2",
27
- md: "gap-4",
28
- lg: "gap-6",
29
- },
30
- },
31
- defaultVariants: {
32
- direction: "col",
33
- spacing: "md",
34
- },
35
- });
36
-
37
- export interface StackProps
38
- extends React.HTMLAttributes<HTMLDivElement>,
39
- VariantProps<typeof stackVariants> {}
40
-
41
- export const Stack = React.forwardRef<HTMLDivElement, StackProps>(
42
- ({ className, direction, align, justify, spacing, ...props }, ref) => {
43
- return (
44
- <div
45
- ref={ref}
46
- className={cn(
47
- stackVariants({ direction, align, justify, spacing }),
48
- className,
49
- )}
50
- {...props}
51
- />
52
- );
53
- },
54
- );
55
- Stack.displayName = "Stack";
@@ -1,128 +0,0 @@
1
- import * as React from "react";
2
- import { cn } from "../../lib/utils";
3
-
4
- export type StatusTone = "success" | "warning" | "danger" | "muted";
5
-
6
- const STATUS_TONE_STYLES: Record<StatusTone, { badge: string; dot: string }> = {
7
- success: {
8
- badge: "text-ok border-ok/30 bg-ok/10",
9
- dot: "bg-ok",
10
- },
11
- warning: {
12
- badge: "text-warn border-warn/30 bg-warn/10",
13
- dot: "bg-warn",
14
- },
15
- danger: {
16
- badge: "text-destructive border-destructive/30 bg-destructive/10",
17
- dot: "bg-destructive",
18
- },
19
- muted: {
20
- badge: "text-muted border-border bg-bg",
21
- dot: "bg-muted",
22
- },
23
- };
24
-
25
- export function statusToneForBoolean(
26
- condition: boolean,
27
- onTone: StatusTone = "success",
28
- offTone: StatusTone = "muted",
29
- ): StatusTone {
30
- return condition ? onTone : offTone;
31
- }
32
-
33
- /* ── StatusBadge ─────────────────────────────────────────────────────── */
34
-
35
- export interface StatusBadgeProps
36
- extends React.HTMLAttributes<HTMLSpanElement> {
37
- label: string;
38
- tone: StatusTone;
39
- withDot?: boolean;
40
- }
41
-
42
- export const StatusBadge = React.forwardRef<HTMLSpanElement, StatusBadgeProps>(
43
- ({ label, tone, withDot = false, className, ...props }, ref) => {
44
- const styles = STATUS_TONE_STYLES[tone];
45
- return (
46
- <span
47
- ref={ref}
48
- className={cn(
49
- "inline-flex items-center gap-1 rounded-sm border px-2 py-0.5 text-[10px] font-bold uppercase",
50
- styles.badge,
51
- className,
52
- )}
53
- {...props}
54
- >
55
- {withDot && (
56
- <span className={cn("h-1.5 w-1.5 rounded-full", styles.dot)} />
57
- )}
58
- {label}
59
- </span>
60
- );
61
- },
62
- );
63
- StatusBadge.displayName = "StatusBadge";
64
-
65
- /* ── StatusDot ───────────────────────────────────────────────────────── */
66
-
67
- export interface StatusDotProps extends React.HTMLAttributes<HTMLSpanElement> {
68
- status: string;
69
- }
70
-
71
- export const StatusDot = React.forwardRef<HTMLSpanElement, StatusDotProps>(
72
- ({ status, className, ...props }, ref) => {
73
- const tone: StatusTone =
74
- status === "success" || status === "completed" || status === "connected"
75
- ? "success"
76
- : status === "error" || status === "failed" || status === "denied"
77
- ? "danger"
78
- : "muted";
79
-
80
- const styles = STATUS_TONE_STYLES[tone];
81
- return (
82
- <span
83
- ref={ref}
84
- className={cn(
85
- "inline-block h-2 w-2 rounded-full",
86
- styles.dot,
87
- className,
88
- )}
89
- {...props}
90
- />
91
- );
92
- },
93
- );
94
- StatusDot.displayName = "StatusDot";
95
-
96
- /* ── StatCard ────────────────────────────────────────────────────────── */
97
-
98
- export interface StatCardProps extends React.HTMLAttributes<HTMLDivElement> {
99
- label: string;
100
- value: React.ReactNode;
101
- accent?: boolean;
102
- }
103
-
104
- export const StatCard = React.forwardRef<HTMLDivElement, StatCardProps>(
105
- ({ label, value, accent = false, className, ...props }, ref) => (
106
- <div
107
- ref={ref}
108
- className={cn(
109
- "flex flex-col items-center justify-center border border-border bg-bg p-3 min-w-[80px]",
110
- className,
111
- )}
112
- {...props}
113
- >
114
- <div
115
- className={cn(
116
- "text-lg font-bold tabular-nums",
117
- accent && "text-accent",
118
- )}
119
- >
120
- {value}
121
- </div>
122
- <div className="mt-0.5 text-[10px] uppercase tracking-wide text-muted">
123
- {label}
124
- </div>
125
- </div>
126
- ),
127
- );
128
- StatCard.displayName = "StatCard";
@@ -1,27 +0,0 @@
1
- import * as SwitchPrimitives from "@radix-ui/react-switch";
2
- import * as React from "react";
3
-
4
- import { cn } from "../../lib/utils";
5
-
6
- const Switch = React.forwardRef<
7
- React.ElementRef<typeof SwitchPrimitives.Root>,
8
- React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
9
- >(({ className, ...props }, ref) => (
10
- <SwitchPrimitives.Root
11
- className={cn(
12
- "peer inline-flex h-[24px] w-[44px] shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-bg disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
13
- className,
14
- )}
15
- {...props}
16
- ref={ref}
17
- >
18
- <SwitchPrimitives.Thumb
19
- className={cn(
20
- "pointer-events-none block h-5 w-5 rounded-full bg-bg shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0",
21
- )}
22
- />
23
- </SwitchPrimitives.Root>
24
- ));
25
- Switch.displayName = SwitchPrimitives.Root.displayName;
26
-
27
- export { Switch };
@@ -1,53 +0,0 @@
1
- import * as TabsPrimitive from "@radix-ui/react-tabs";
2
- import * as React from "react";
3
-
4
- import { cn } from "../../lib/utils";
5
-
6
- const Tabs = TabsPrimitive.Root;
7
-
8
- const TabsList = React.forwardRef<
9
- React.ElementRef<typeof TabsPrimitive.List>,
10
- React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
11
- >(({ className, ...props }, ref) => (
12
- <TabsPrimitive.List
13
- ref={ref}
14
- className={cn(
15
- "inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-fg",
16
- className,
17
- )}
18
- {...props}
19
- />
20
- ));
21
- TabsList.displayName = TabsPrimitive.List.displayName;
22
-
23
- const TabsTrigger = React.forwardRef<
24
- React.ElementRef<typeof TabsPrimitive.Trigger>,
25
- React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
26
- >(({ className, ...props }, ref) => (
27
- <TabsPrimitive.Trigger
28
- ref={ref}
29
- className={cn(
30
- "inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-bg transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-bg data-[state=active]:text-txt data-[state=active]:shadow-sm",
31
- className,
32
- )}
33
- {...props}
34
- />
35
- ));
36
- TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
37
-
38
- const TabsContent = React.forwardRef<
39
- React.ElementRef<typeof TabsPrimitive.Content>,
40
- React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
41
- >(({ className, ...props }, ref) => (
42
- <TabsPrimitive.Content
43
- ref={ref}
44
- className={cn(
45
- "mt-2 ring-offset-bg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
46
- className,
47
- )}
48
- {...props}
49
- />
50
- ));
51
- TabsContent.displayName = TabsPrimitive.Content.displayName;
52
-
53
- export { Tabs, TabsContent, TabsList, TabsTrigger };
@@ -1,111 +0,0 @@
1
- /**
2
- * TagEditor — add/remove string tags with chip display.
3
- *
4
- * Fully generic; no app-context dependency. Callers pass translated labels
5
- * via props (with English defaults so the component works out-of-the-box).
6
- */
7
-
8
- import { useState } from "react";
9
- import { cn } from "../../lib/utils";
10
- import { Button } from "./button";
11
- import { Input } from "./input";
12
-
13
- export interface TagEditorProps {
14
- label: string;
15
- items: string[];
16
- onChange: (items: string[]) => void;
17
- placeholder?: string;
18
- /** Label for the Add button. Defaults to "Add". */
19
- addLabel?: string;
20
- /** Label for the remove button. Defaults to "×". */
21
- removeLabel?: string;
22
- /** Optional class for the root container. */
23
- className?: string;
24
- /** Optional class for the input row. */
25
- inputRowClassName?: string;
26
- /** Optional class for the scrollable tag list. */
27
- listClassName?: string;
28
- }
29
-
30
- export function TagEditor({
31
- label,
32
- items,
33
- onChange,
34
- placeholder = "add item...",
35
- addLabel = "+",
36
- removeLabel = "×",
37
- className,
38
- inputRowClassName,
39
- listClassName,
40
- }: TagEditorProps) {
41
- const [inputValue, setInputValue] = useState("");
42
-
43
- const addItem = () => {
44
- const trimmed = inputValue.trim();
45
- if (trimmed && !items.includes(trimmed)) {
46
- onChange([...items, trimmed]);
47
- }
48
- setInputValue("");
49
- };
50
-
51
- const removeItem = (index: number) => {
52
- const updated = [...items];
53
- updated.splice(index, 1);
54
- onChange(updated);
55
- };
56
-
57
- return (
58
- <div className={cn("flex min-h-0 flex-col gap-1.5", className)}>
59
- <span className="font-semibold text-xs">{label}</span>
60
- <div className={cn("flex items-center gap-1.5", inputRowClassName)}>
61
- <Input
62
- type="text"
63
- value={inputValue}
64
- placeholder={placeholder}
65
- onChange={(e) => setInputValue(e.target.value)}
66
- onKeyDown={(e) => {
67
- if (e.key === "Enter") {
68
- e.preventDefault();
69
- addItem();
70
- }
71
- }}
72
- className="h-7 px-2 border-border bg-card text-[11px] focus-visible:ring-1 focus-visible:ring-accent flex-1 min-w-0 shadow-sm"
73
- />
74
- <Button
75
- variant="ghost"
76
- size="sm"
77
- className="h-7 w-7 text-[14px] p-0 text-accent border-none hover:bg-transparent hover:text-accent/80 font-bold"
78
- onClick={addItem}
79
- >
80
- {addLabel}
81
- </Button>
82
- </div>
83
- <div
84
- className={cn(
85
- "min-h-0 overflow-y-auto rounded-xl border border-border/40 bg-bg/50 p-2 backdrop-blur-sm",
86
- "flex flex-wrap content-start items-start gap-x-1.5 gap-y-1",
87
- listClassName,
88
- )}
89
- >
90
- {items.map((item, i) => (
91
- <span
92
- key={item}
93
- className="inline-flex items-center justify-between gap-1 px-2 py-0.5 border border-border/50 bg-black/10 rounded text-[11px] h-fit text-txt font-medium"
94
- >
95
- <span className="truncate max-w-[200px]" title={item}>
96
- {item}
97
- </span>
98
- <Button
99
- variant="ghost"
100
- size="icon"
101
- className="h-4 w-4 p-0 text-danger/80 hover:text-danger hover:bg-transparent"
102
- onClick={() => removeItem(i)}
103
- >
104
- {removeLabel}
105
- </Button>
106
- </span>
107
- ))}
108
- </div>
109
- </div>
110
- );
111
- }
@@ -1,108 +0,0 @@
1
- import { X } from "lucide-react";
2
- import * as React from "react";
3
- import { cn } from "../../lib/utils";
4
-
5
- export interface TagInputProps
6
- extends Omit<React.HTMLAttributes<HTMLDivElement>, "onChange"> {
7
- /** Label shown above the input */
8
- label?: string;
9
- /** Current list of tags */
10
- items: string[];
11
- /** Called with the updated tag list */
12
- onChange: (items: string[]) => void;
13
- /** Placeholder text for the input */
14
- placeholder?: string;
15
- /** Maximum number of tags */
16
- maxItems?: number;
17
- /** Label for the explicit add button */
18
- addLabel?: string;
19
- /** Aria-label template for the remove button */
20
- removeLabel?: string;
21
- }
22
-
23
- export const TagInput = React.forwardRef<HTMLDivElement, TagInputProps>(
24
- (
25
- {
26
- label,
27
- items,
28
- onChange,
29
- placeholder = "Add item…",
30
- maxItems,
31
- addLabel = "Add",
32
- removeLabel = "Remove",
33
- className,
34
- ...props
35
- },
36
- ref,
37
- ) => {
38
- const [inputValue, setInputValue] = React.useState("");
39
-
40
- const addItem = React.useCallback(() => {
41
- const trimmed = inputValue.trim();
42
- if (!trimmed || items.includes(trimmed)) return;
43
- if (maxItems != null && items.length >= maxItems) return;
44
- onChange([...items, trimmed]);
45
- setInputValue("");
46
- }, [inputValue, items, onChange, maxItems]);
47
-
48
- const removeItem = React.useCallback(
49
- (index: number) => {
50
- const updated = [...items];
51
- updated.splice(index, 1);
52
- onChange(updated);
53
- },
54
- [items, onChange],
55
- );
56
-
57
- return (
58
- <div
59
- ref={ref}
60
- className={cn("flex flex-col gap-1.5", className)}
61
- {...props}
62
- >
63
- {label && <span className="text-xs font-semibold">{label}</span>}
64
- <div className="flex items-center gap-1.5">
65
- <input
66
- type="text"
67
- value={inputValue}
68
- placeholder={placeholder}
69
- onChange={(e) => setInputValue(e.target.value)}
70
- onKeyDown={(e) => {
71
- if (e.key === "Enter") {
72
- e.preventDefault();
73
- addItem();
74
- }
75
- }}
76
- className="flex-1 min-w-0 rounded-md border border-input bg-bg px-2 py-1 text-[11px] placeholder:text-muted focus-visible:outline-none focus-visible:border-ring"
77
- />
78
- <button
79
- type="button"
80
- className="rounded-md border border-input bg-bg px-1.5 py-0.5 text-[10px] text-muted transition-colors hover:border-accent hover:text-accent"
81
- onClick={addItem}
82
- >
83
- {addLabel}
84
- </button>
85
- </div>
86
- <div className="flex flex-wrap gap-1.5 rounded-md border border-border bg-bg-accent p-1.5 min-h-[60px] content-start">
87
- {items.map((item, i) => (
88
- <span
89
- key={item}
90
- className="inline-flex items-center gap-1 rounded-sm border border-border bg-bg px-2 py-0.5 text-[11px]"
91
- >
92
- {item}
93
- <button
94
- type="button"
95
- className="text-muted hover:text-destructive transition-colors"
96
- onClick={() => removeItem(i)}
97
- aria-label={`${removeLabel} ${item}`}
98
- >
99
- <X className="h-3 w-3" />
100
- </button>
101
- </span>
102
- ))}
103
- </div>
104
- </div>
105
- );
106
- },
107
- );
108
- TagInput.displayName = "TagInput";
@@ -1,24 +0,0 @@
1
- import * as React from "react";
2
-
3
- import { cn } from "../../lib/utils";
4
-
5
- export interface TextareaProps
6
- extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
7
-
8
- const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
9
- ({ className, ...props }, ref) => {
10
- return (
11
- <textarea
12
- className={cn(
13
- "flex min-h-[80px] w-full rounded-md border border-input bg-bg px-3 py-2 text-sm ring-offset-bg placeholder:text-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
14
- className,
15
- )}
16
- ref={ref}
17
- {...props}
18
- />
19
- );
20
- },
21
- );
22
- Textarea.displayName = "Textarea";
23
-
24
- export { Textarea };