@sero-ai/ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/.turbo/turbo-typecheck.log +4 -0
  2. package/components.json +18 -0
  3. package/package.json +70 -0
  4. package/src/components/ai-elements/agent.tsx +142 -0
  5. package/src/components/ai-elements/artifact.tsx +149 -0
  6. package/src/components/ai-elements/attachments.tsx +427 -0
  7. package/src/components/ai-elements/audio-player.tsx +232 -0
  8. package/src/components/ai-elements/canvas.tsx +26 -0
  9. package/src/components/ai-elements/chain-of-thought.tsx +223 -0
  10. package/src/components/ai-elements/checkpoint.tsx +72 -0
  11. package/src/components/ai-elements/code-block.tsx +555 -0
  12. package/src/components/ai-elements/commit.tsx +449 -0
  13. package/src/components/ai-elements/confirmation.tsx +173 -0
  14. package/src/components/ai-elements/connection.tsx +28 -0
  15. package/src/components/ai-elements/context.tsx +410 -0
  16. package/src/components/ai-elements/controls.tsx +19 -0
  17. package/src/components/ai-elements/conversation.tsx +167 -0
  18. package/src/components/ai-elements/edge.tsx +144 -0
  19. package/src/components/ai-elements/environment-variables.tsx +325 -0
  20. package/src/components/ai-elements/file-tree.tsx +298 -0
  21. package/src/components/ai-elements/image.tsx +25 -0
  22. package/src/components/ai-elements/inline-citation.tsx +294 -0
  23. package/src/components/ai-elements/jsx-preview.tsx +250 -0
  24. package/src/components/ai-elements/message.tsx +359 -0
  25. package/src/components/ai-elements/mic-selector.tsx +372 -0
  26. package/src/components/ai-elements/model-selector.tsx +214 -0
  27. package/src/components/ai-elements/node.tsx +72 -0
  28. package/src/components/ai-elements/open-in-chat.tsx +367 -0
  29. package/src/components/ai-elements/package-info.tsx +235 -0
  30. package/src/components/ai-elements/panel.tsx +16 -0
  31. package/src/components/ai-elements/persona.tsx +280 -0
  32. package/src/components/ai-elements/plan.tsx +144 -0
  33. package/src/components/ai-elements/prompt-input.tsx +1341 -0
  34. package/src/components/ai-elements/queue.tsx +275 -0
  35. package/src/components/ai-elements/reasoning.tsx +229 -0
  36. package/src/components/ai-elements/sandbox.tsx +133 -0
  37. package/src/components/ai-elements/schema-display.tsx +473 -0
  38. package/src/components/ai-elements/shimmer.tsx +78 -0
  39. package/src/components/ai-elements/snippet.tsx +141 -0
  40. package/src/components/ai-elements/sources.tsx +78 -0
  41. package/src/components/ai-elements/speech-input.tsx +324 -0
  42. package/src/components/ai-elements/stack-trace.tsx +531 -0
  43. package/src/components/ai-elements/suggestion.tsx +58 -0
  44. package/src/components/ai-elements/task.tsx +88 -0
  45. package/src/components/ai-elements/terminal.tsx +277 -0
  46. package/src/components/ai-elements/test-results.tsx +497 -0
  47. package/src/components/ai-elements/tool.tsx +174 -0
  48. package/src/components/ai-elements/toolbar.tsx +17 -0
  49. package/src/components/ai-elements/transcription.tsx +126 -0
  50. package/src/components/ai-elements/voice-selector.tsx +525 -0
  51. package/src/components/ai-elements/web-preview.tsx +282 -0
  52. package/src/components/ui/accordion.tsx +64 -0
  53. package/src/components/ui/alert-dialog.tsx +196 -0
  54. package/src/components/ui/alert.tsx +66 -0
  55. package/src/components/ui/aspect-ratio.tsx +11 -0
  56. package/src/components/ui/avatar.tsx +107 -0
  57. package/src/components/ui/badge.tsx +48 -0
  58. package/src/components/ui/breadcrumb.tsx +109 -0
  59. package/src/components/ui/button-group.tsx +83 -0
  60. package/src/components/ui/button.tsx +64 -0
  61. package/src/components/ui/calendar.tsx +218 -0
  62. package/src/components/ui/card.tsx +92 -0
  63. package/src/components/ui/carousel.tsx +239 -0
  64. package/src/components/ui/chart.tsx +355 -0
  65. package/src/components/ui/checkbox.tsx +32 -0
  66. package/src/components/ui/collapsible.tsx +31 -0
  67. package/src/components/ui/combobox.tsx +310 -0
  68. package/src/components/ui/command.tsx +184 -0
  69. package/src/components/ui/context-menu.tsx +252 -0
  70. package/src/components/ui/dialog.tsx +158 -0
  71. package/src/components/ui/direction.tsx +22 -0
  72. package/src/components/ui/drawer.tsx +133 -0
  73. package/src/components/ui/dropdown-menu.tsx +257 -0
  74. package/src/components/ui/empty.tsx +104 -0
  75. package/src/components/ui/field.tsx +248 -0
  76. package/src/components/ui/form.tsx +165 -0
  77. package/src/components/ui/hover-card.tsx +42 -0
  78. package/src/components/ui/input-group.tsx +168 -0
  79. package/src/components/ui/input-otp.tsx +77 -0
  80. package/src/components/ui/input.tsx +21 -0
  81. package/src/components/ui/item.tsx +193 -0
  82. package/src/components/ui/kbd.tsx +28 -0
  83. package/src/components/ui/label.tsx +22 -0
  84. package/src/components/ui/menubar.tsx +276 -0
  85. package/src/components/ui/native-select.tsx +53 -0
  86. package/src/components/ui/navigation-menu.tsx +168 -0
  87. package/src/components/ui/pagination.tsx +127 -0
  88. package/src/components/ui/popover.tsx +87 -0
  89. package/src/components/ui/progress.tsx +31 -0
  90. package/src/components/ui/radio-group.tsx +43 -0
  91. package/src/components/ui/resizable.tsx +53 -0
  92. package/src/components/ui/scroll-area.tsx +56 -0
  93. package/src/components/ui/select.tsx +190 -0
  94. package/src/components/ui/separator.tsx +28 -0
  95. package/src/components/ui/sheet.tsx +145 -0
  96. package/src/components/ui/sidebar.tsx +724 -0
  97. package/src/components/ui/skeleton.tsx +13 -0
  98. package/src/components/ui/slider.tsx +61 -0
  99. package/src/components/ui/sonner.tsx +40 -0
  100. package/src/components/ui/spinner.tsx +16 -0
  101. package/src/components/ui/switch.tsx +33 -0
  102. package/src/components/ui/table.tsx +116 -0
  103. package/src/components/ui/tabs.tsx +91 -0
  104. package/src/components/ui/textarea.tsx +18 -0
  105. package/src/components/ui/toggle-group.tsx +83 -0
  106. package/src/components/ui/toggle.tsx +47 -0
  107. package/src/components/ui/tooltip.tsx +57 -0
  108. package/src/components/ui/tree.tsx +207 -0
  109. package/src/hooks/use-mobile.ts +17 -0
  110. package/src/index.ts +16 -0
  111. package/src/lib/utils.ts +6 -0
  112. package/src/styles/globals.css +373 -0
  113. package/tsconfig.json +18 -0
@@ -0,0 +1,207 @@
1
+ "use client";
2
+
3
+ import type { ItemInstance } from "@headless-tree/core";
4
+ import { ChevronDownIcon } from "lucide-react";
5
+ import { Slot } from "radix-ui";
6
+ import * as React from "react";
7
+
8
+ import { cn } from "../../lib/utils";
9
+
10
+ interface TreeContextValue<T = any> {
11
+ indent: number;
12
+ currentItem?: ItemInstance<T>;
13
+ tree?: any;
14
+ }
15
+
16
+ const TreeContext = React.createContext<TreeContextValue>({
17
+ currentItem: undefined,
18
+ indent: 20,
19
+ tree: undefined,
20
+ });
21
+
22
+ function useTreeContext<T = any>() {
23
+ return React.useContext(TreeContext) as TreeContextValue<T>;
24
+ }
25
+
26
+ interface TreeProps extends React.HTMLAttributes<HTMLDivElement> {
27
+ indent?: number;
28
+ tree?: any;
29
+ }
30
+
31
+ function Tree({ indent = 20, tree, className, ...props }: TreeProps) {
32
+ const containerProps =
33
+ tree && typeof tree.getContainerProps === "function"
34
+ ? tree.getContainerProps()
35
+ : {};
36
+ const mergedProps = { ...props, ...containerProps };
37
+ const { style: propStyle, ...otherProps } = mergedProps;
38
+
39
+ const mergedStyle = {
40
+ ...propStyle,
41
+ "--tree-indent": `${indent}px`,
42
+ } as React.CSSProperties;
43
+
44
+ return (
45
+ <TreeContext.Provider value={{ indent, tree }}>
46
+ <div
47
+ className={cn("flex flex-col", className)}
48
+ data-slot="tree"
49
+ style={mergedStyle}
50
+ {...otherProps}
51
+ />
52
+ </TreeContext.Provider>
53
+ );
54
+ }
55
+
56
+ interface TreeItemProps<T = any>
57
+ extends React.HTMLAttributes<HTMLButtonElement> {
58
+ item: ItemInstance<T>;
59
+ indent?: number;
60
+ asChild?: boolean;
61
+ }
62
+
63
+ /**
64
+ * TreeItem — full-width row button.
65
+ *
66
+ * The row carries hover / selected / drag-target backgrounds so the
67
+ * highlight spans edge-to-edge (VSCode-style). Indentation is applied
68
+ * via `paddingInlineStart` so the background is unaffected.
69
+ */
70
+ function TreeItem<T = any>({
71
+ item,
72
+ className,
73
+ asChild,
74
+ children,
75
+ ...props
76
+ }: Omit<TreeItemProps<T>, "indent">) {
77
+ const { indent } = useTreeContext<T>();
78
+
79
+ const itemProps = typeof item.getProps === "function" ? item.getProps() : {};
80
+ const mergedProps = { ...props, ...itemProps };
81
+ const { style: propStyle, ...otherProps } = mergedProps;
82
+
83
+ const treePadding = item.getItemMeta().level * indent;
84
+ const mergedStyle = {
85
+ ...propStyle,
86
+ "--tree-padding": `${treePadding}px`,
87
+ paddingInlineStart: `${treePadding}px`,
88
+ } as React.CSSProperties;
89
+
90
+ const Comp = asChild ? Slot.Root : "button";
91
+
92
+ return (
93
+ <TreeContext.Provider value={{ currentItem: item, indent }}>
94
+ <Comp
95
+ aria-expanded={item.isExpanded()}
96
+ className={cn(
97
+ "z-10 w-full select-none ps-(--tree-padding) outline-hidden",
98
+ "transition-colors",
99
+ "focus:z-20 data-disabled:pointer-events-none data-disabled:opacity-50",
100
+ className,
101
+ )}
102
+ data-drag-target={
103
+ typeof item.isDragTarget === "function"
104
+ ? item.isDragTarget() || false
105
+ : undefined
106
+ }
107
+ data-focus={
108
+ typeof item.isFocused === "function"
109
+ ? item.isFocused() || false
110
+ : undefined
111
+ }
112
+ data-folder={
113
+ typeof item.isFolder === "function"
114
+ ? item.isFolder() || false
115
+ : undefined
116
+ }
117
+ data-search-match={
118
+ typeof item.isMatchingSearch === "function"
119
+ ? item.isMatchingSearch() || false
120
+ : undefined
121
+ }
122
+ data-selected={
123
+ typeof item.isSelected === "function"
124
+ ? item.isSelected() || false
125
+ : undefined
126
+ }
127
+ data-slot="tree-item"
128
+ style={mergedStyle}
129
+ {...otherProps}
130
+ >
131
+ {children}
132
+ </Comp>
133
+ </TreeContext.Provider>
134
+ );
135
+ }
136
+
137
+ interface TreeItemLabelProps<T = any>
138
+ extends React.HTMLAttributes<HTMLSpanElement> {
139
+ item?: ItemInstance<T>;
140
+ }
141
+
142
+ /**
143
+ * TreeItemLabel — content wrapper inside a TreeItem.
144
+ *
145
+ * Layout-only (chevron + children). Background lives on the parent
146
+ * TreeItem so it spans the full row width.
147
+ */
148
+ function TreeItemLabel<T = any>({
149
+ item: propItem,
150
+ children,
151
+ className,
152
+ ...props
153
+ }: TreeItemLabelProps<T>) {
154
+ const { currentItem } = useTreeContext<T>();
155
+ const item = propItem || currentItem;
156
+
157
+ if (!item) {
158
+ console.warn("TreeItemLabel: No item provided via props or context");
159
+ return null;
160
+ }
161
+
162
+ return (
163
+ <span
164
+ className={cn(
165
+ "flex min-w-0 items-center gap-1 px-2 py-1",
166
+ "[&_svg]:pointer-events-none [&_svg]:shrink-0",
167
+ className,
168
+ )}
169
+ data-slot="tree-item-label"
170
+ {...props}
171
+ >
172
+ {item.isFolder() && (
173
+ <ChevronDownIcon className="in-aria-[expanded=false]:-rotate-90 size-4 shrink-0 text-muted-foreground" />
174
+ )}
175
+ {children ||
176
+ (typeof item.getItemName === "function" ? item.getItemName() : null)}
177
+ </span>
178
+ );
179
+ }
180
+
181
+ function TreeDragLine({
182
+ className,
183
+ ...props
184
+ }: React.HTMLAttributes<HTMLDivElement>) {
185
+ const { tree } = useTreeContext();
186
+
187
+ if (!tree || typeof tree.getDragLineStyle !== "function") {
188
+ console.warn(
189
+ "TreeDragLine: No tree provided via context or tree does not have getDragLineStyle method",
190
+ );
191
+ return null;
192
+ }
193
+
194
+ const dragLine = tree.getDragLineStyle();
195
+ return (
196
+ <div
197
+ className={cn(
198
+ "-mt-px before:-top-[3px] absolute z-30 h-0.5 w-[unset] bg-primary before:absolute before:left-0 before:size-2 before:rounded-full before:border-2 before:border-primary before:bg-background",
199
+ className,
200
+ )}
201
+ style={dragLine}
202
+ {...props}
203
+ />
204
+ );
205
+ }
206
+
207
+ export { Tree, TreeItem, TreeItemLabel, TreeDragLine };
@@ -0,0 +1,17 @@
1
+ import { useState, useEffect } from 'react';
2
+
3
+ const MOBILE_BREAKPOINT = 768;
4
+
5
+ export function useIsMobile() {
6
+ const [isMobile, setIsMobile] = useState(false);
7
+
8
+ useEffect(() => {
9
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
10
+ const onChange = () => setIsMobile(mql.matches);
11
+ mql.addEventListener('change', onChange);
12
+ setIsMobile(mql.matches);
13
+ return () => mql.removeEventListener('change', onChange);
14
+ }, []);
15
+
16
+ return isMobile;
17
+ }
package/src/index.ts ADDED
@@ -0,0 +1,16 @@
1
+ // @sero-ai/ui — Shared UI components, AI elements, and utilities
2
+ //
3
+ // Consumers can import from subpaths for tree-shakeable access:
4
+ // import { Button } from "@sero-ai/ui/components/ui/button"
5
+ // import { Message } from "@sero-ai/ui/components/ai-elements/message"
6
+ // import { cn } from "@sero-ai/ui/lib/utils"
7
+ // import { useIsMobile } from "@sero-ai/ui/hooks/use-mobile"
8
+ //
9
+ // Or import the barrel export:
10
+ // import { cn, useIsMobile } from "@sero-ai/ui"
11
+
12
+ // ── Utilities ──
13
+ export { cn } from "./lib/utils";
14
+
15
+ // ── Hooks ──
16
+ export { useIsMobile } from "./hooks/use-mobile";
@@ -0,0 +1,6 @@
1
+ import { clsx, type ClassValue } from "clsx"
2
+ import { twMerge } from "tailwind-merge"
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs))
6
+ }
@@ -0,0 +1,373 @@
1
+ @import "tailwindcss";
2
+ @import "tw-animate-css";
3
+ @import "shadcn/tailwind.css";
4
+
5
+ /* Ensure monorepo consumers that @import this file also scan @sero-ai/ui
6
+ component sources for Tailwind utility classes. Without this, complex
7
+ classes like has-[>[data-align=block-end]]:flex-col won't be generated. */
8
+ @source "../components";
9
+
10
+ @custom-variant dark (&:is(.dark *));
11
+
12
+ /* ── Sero Design System ──────────────────────────────────────── */
13
+
14
+ :root {
15
+ /* Surface colors (light) */
16
+ --bg-base: #ffffff;
17
+ --bg-surface: #f4f5f7;
18
+ --bg-elevated: #eaecf0;
19
+ --bg-overlay: #dde0e6;
20
+ --bg-muted: #c8ccd4;
21
+
22
+ /* Border (light) */
23
+ --border-subtle: #d4d8e0;
24
+ --border-default: #bcc1cc;
25
+ --border-focus: #6366f1;
26
+
27
+ /* Text (light) */
28
+ --text-primary: #0f1117;
29
+ --text-secondary: #3b4252;
30
+ --text-muted: #6b7280;
31
+ --text-inverse: #fafafa;
32
+
33
+ /* Accent (indigo) — brand accent colour used by Sero components */
34
+ --accent-primary: #6366f1;
35
+ --accent-hover: #818cf8;
36
+ --accent-muted: #6366f11a;
37
+ --accent-code: #7c3aed;
38
+
39
+ /* Status — solid */
40
+ --status-success: #16a34a;
41
+ --status-warning: #d97706;
42
+ --status-error: #dc2626;
43
+ --status-info: #2563eb;
44
+
45
+ /* Status — muted backgrounds (low-opacity tints) */
46
+ --status-success-muted: rgba(22, 163, 74, 0.10);
47
+ --status-warning-muted: rgba(217, 119, 6, 0.10);
48
+ --status-error-muted: rgba(220, 38, 38, 0.10);
49
+ --status-info-muted: rgba(37, 99, 235, 0.10);
50
+
51
+ /* Status — subtle (slightly stronger tint for borders, badges) */
52
+ --status-success-subtle: rgba(22, 163, 74, 0.15);
53
+ --status-warning-subtle: rgba(217, 119, 6, 0.15);
54
+ --status-error-subtle: rgba(220, 38, 38, 0.15);
55
+ --status-info-subtle: rgba(37, 99, 235, 0.15);
56
+
57
+ /* Status — faint (near-invisible tint for full-area backgrounds) */
58
+ --status-success-faint: rgba(22, 163, 74, 0.03);
59
+ --status-warning-faint: rgba(217, 119, 6, 0.03);
60
+ --status-error-faint: rgba(220, 38, 38, 0.03);
61
+ --status-info-faint: rgba(37, 99, 235, 0.03);
62
+
63
+ /* Status — border (20% opacity for bordered containers) */
64
+ --status-success-border: rgba(22, 163, 74, 0.20);
65
+ --status-warning-border: rgba(217, 119, 6, 0.20);
66
+ --status-error-border: rgba(220, 38, 38, 0.20);
67
+ --status-info-border: rgba(37, 99, 235, 0.20);
68
+
69
+ /* Semantic colours — collaboration / special modes */
70
+ --collab-primary: #7c3aed;
71
+ --collab-primary-muted: rgba(124, 58, 237, 0.10);
72
+ --collab-primary-subtle: rgba(124, 58, 237, 0.15);
73
+ --collab-primary-border: rgba(124, 58, 237, 0.20);
74
+
75
+ /* Semantic colours — voice / recording */
76
+ --voice-recording: #f43f5e;
77
+ --voice-recording-muted: rgba(244, 63, 94, 0.20);
78
+ --voice-processing: #06b6d4;
79
+ --voice-processing-muted: rgba(6, 182, 212, 0.15);
80
+
81
+ /* Semantic colours — indigo accent for notifications/banners */
82
+ --banner-primary: #6366f1;
83
+ --banner-primary-muted: rgba(99, 102, 241, 0.10);
84
+ --banner-primary-subtle: rgba(99, 102, 241, 0.15);
85
+ --banner-primary-border: rgba(99, 102, 241, 0.20);
86
+
87
+ /* Thinking / reasoning gradients */
88
+ --gradient-thinking-high: linear-gradient(135deg, rgba(245, 158, 11, 0.20), rgba(239, 68, 68, 0.20));
89
+ --gradient-thinking-low: linear-gradient(135deg, rgba(99, 102, 241, 0.20), rgba(139, 92, 246, 0.20));
90
+
91
+ /* File type icon colours */
92
+ --file-icon-ts: #3b82f6;
93
+ --file-icon-js: #eab308;
94
+ --file-icon-json: #22c55e;
95
+ --file-icon-css: #6366f1;
96
+ --file-icon-rust: #f97316;
97
+ --file-icon-markdown: #6366f1;
98
+ --file-icon-default: var(--text-muted);
99
+
100
+ /* Typography (themeable) */
101
+ --font-sans: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
102
+ --font-mono: 'JetBrains Mono', 'SF Mono', 'Fira Code', 'Cascadia Code', Menlo, monospace;
103
+ --font-size-base: 14px;
104
+
105
+ /* Spacing */
106
+ --space-xs: 4px;
107
+ --space-sm: 8px;
108
+ --space-md: 12px;
109
+ --space-lg: 16px;
110
+ --space-xl: 24px;
111
+
112
+ /* Sero radius (legacy — use Tailwind rounded-* for new components) */
113
+ --sero-radius-sm: 4px;
114
+ --sero-radius-md: 8px;
115
+ --sero-radius-lg: 12px;
116
+
117
+ /* Sero font sizes (legacy — use Tailwind text-* for new components) */
118
+ --sero-text-xs: 12px;
119
+ --sero-text-sm: 13px;
120
+ --sero-text-base: 14px;
121
+ --sero-text-lg: 15px;
122
+ --sero-text-xl: 16px;
123
+
124
+ /* Transition */
125
+ --transition-fast: 120ms ease;
126
+ --transition-normal: 200ms ease;
127
+ --radius: 0.625rem;
128
+
129
+ /* ── shadcn bridge ────────────────────────────────────────
130
+ Derive shadcn/ui tokens from Sero design tokens so every
131
+ shadcn component (Dialog, Command, Dropdown, Tooltip, …)
132
+ automatically follows theme changes.
133
+ NOTE: --accent here is the shadcn "hover/selection bg",
134
+ NOT the brand accent colour (that's --accent-primary). */
135
+ --background: var(--bg-base);
136
+ --foreground: var(--text-primary);
137
+ --card: var(--bg-surface);
138
+ --card-foreground: var(--text-primary);
139
+ --popover: var(--bg-elevated);
140
+ --popover-foreground: var(--text-primary);
141
+ --primary: var(--text-primary);
142
+ --primary-foreground: var(--text-inverse);
143
+ --secondary: var(--bg-surface);
144
+ --secondary-foreground: var(--text-primary);
145
+ --muted: var(--bg-muted);
146
+ --muted-foreground: var(--text-muted);
147
+ --accent: var(--bg-overlay);
148
+ --accent-foreground: var(--text-primary);
149
+ --destructive: var(--status-error);
150
+ --border: var(--border-default);
151
+ --input: var(--border-subtle);
152
+ --ring: var(--border-focus);
153
+ --chart-1: oklch(0.646 0.222 41.116);
154
+ --chart-2: oklch(0.6 0.118 184.704);
155
+ --chart-3: oklch(0.398 0.07 227.392);
156
+ --chart-4: oklch(0.828 0.189 84.429);
157
+ --chart-5: oklch(0.769 0.188 70.08);
158
+ --sidebar: var(--bg-surface);
159
+ --sidebar-foreground: var(--text-primary);
160
+ --sidebar-primary: var(--accent-primary);
161
+ --sidebar-primary-foreground: var(--text-inverse);
162
+ --sidebar-accent: var(--bg-elevated);
163
+ --sidebar-accent-foreground: var(--text-primary);
164
+ --sidebar-border: var(--border-subtle);
165
+ --sidebar-ring: var(--border-focus);
166
+ }
167
+
168
+ /* ── Scrollbars ─────────────────────────────────────────────── */
169
+ ::-webkit-scrollbar {
170
+ width: 6px;
171
+ height: 6px;
172
+ }
173
+
174
+ ::-webkit-scrollbar-track {
175
+ background: transparent;
176
+ }
177
+
178
+ ::-webkit-scrollbar-thumb {
179
+ background: var(--border-default);
180
+ border-radius: 3px;
181
+ }
182
+
183
+ ::-webkit-scrollbar-thumb:hover {
184
+ background: var(--text-muted);
185
+ }
186
+
187
+ /* ── Selection ──────────────────────────────────────────────── */
188
+ ::selection {
189
+ background: var(--accent-muted);
190
+ color: var(--text-primary);
191
+ }
192
+
193
+ /* ── Focus ──────────────────────────────────────────────────── */
194
+ /* Scoped to avoid conflicting with shadcn/Radix components which
195
+ manage their own focus rings via Tailwind ring utilities. */
196
+ :focus-visible:not([data-slot]) {
197
+ outline: 2px solid var(--border-focus);
198
+ outline-offset: -2px;
199
+ }
200
+
201
+ @theme inline {
202
+ --radius-sm: calc(var(--radius) - 4px);
203
+ --radius-md: calc(var(--radius) - 2px);
204
+ --radius-lg: var(--radius);
205
+ --radius-xl: calc(var(--radius) + 4px);
206
+ --radius-2xl: calc(var(--radius) + 8px);
207
+ --radius-3xl: calc(var(--radius) + 12px);
208
+ --radius-4xl: calc(var(--radius) + 16px);
209
+ --color-background: var(--background);
210
+ --color-foreground: var(--foreground);
211
+ --color-card: var(--card);
212
+ --color-card-foreground: var(--card-foreground);
213
+ --color-popover: var(--popover);
214
+ --color-popover-foreground: var(--popover-foreground);
215
+ --color-primary: var(--primary);
216
+ --color-primary-foreground: var(--primary-foreground);
217
+ --color-secondary: var(--secondary);
218
+ --color-secondary-foreground: var(--secondary-foreground);
219
+ --color-muted: var(--muted);
220
+ --color-muted-foreground: var(--muted-foreground);
221
+ --color-accent: var(--accent);
222
+ --color-accent-foreground: var(--accent-foreground);
223
+ --color-destructive: var(--destructive);
224
+ --color-border: var(--border);
225
+ --color-input: var(--input);
226
+ --color-ring: var(--ring);
227
+ --color-chart-1: var(--chart-1);
228
+ --color-chart-2: var(--chart-2);
229
+ --color-chart-3: var(--chart-3);
230
+ --color-chart-4: var(--chart-4);
231
+ --color-chart-5: var(--chart-5);
232
+ --color-sidebar: var(--sidebar);
233
+ --color-sidebar-foreground: var(--sidebar-foreground);
234
+ --color-sidebar-primary: var(--sidebar-primary);
235
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
236
+ --color-sidebar-accent: var(--sidebar-accent);
237
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
238
+ --color-sidebar-border: var(--sidebar-border);
239
+ --color-sidebar-ring: var(--sidebar-ring);
240
+ }
241
+
242
+ .dark {
243
+ /* Surface colors (dark) */
244
+ --bg-base: #0a0a0b;
245
+ --bg-surface: #111113;
246
+ --bg-elevated: #18181b;
247
+ --bg-overlay: #1f1f23;
248
+ --bg-muted: #27272a;
249
+
250
+ /* Border (dark) */
251
+ --border-subtle: #27272a;
252
+ --border-default: #3f3f46;
253
+
254
+ /* Text (dark) */
255
+ --text-primary: #fafafa;
256
+ --text-secondary: #a1a1aa;
257
+ --text-muted: #71717a;
258
+ --text-inverse: #09090b;
259
+
260
+ /* Accent (dark) */
261
+ --accent-primary: #818cf8;
262
+ --accent-hover: #a5b4fc;
263
+ --accent-muted: #6366f133;
264
+ --accent-code: #c4b5fd;
265
+
266
+ /* Status — solid (dark) */
267
+ --status-success: #22c55e;
268
+ --status-warning: #f59e0b;
269
+ --status-error: #ef4444;
270
+ --status-info: #3b82f6;
271
+
272
+ /* Status — muted backgrounds (dark) */
273
+ --status-success-muted: rgba(34, 197, 94, 0.10);
274
+ --status-warning-muted: rgba(245, 158, 11, 0.10);
275
+ --status-error-muted: rgba(239, 68, 68, 0.10);
276
+ --status-info-muted: rgba(59, 130, 246, 0.10);
277
+
278
+ /* Status — subtle (dark) */
279
+ --status-success-subtle: rgba(34, 197, 94, 0.15);
280
+ --status-warning-subtle: rgba(245, 158, 11, 0.15);
281
+ --status-error-subtle: rgba(239, 68, 68, 0.15);
282
+ --status-info-subtle: rgba(59, 130, 246, 0.15);
283
+
284
+ /* Status — faint (dark) */
285
+ --status-success-faint: rgba(34, 197, 94, 0.03);
286
+ --status-warning-faint: rgba(245, 158, 11, 0.03);
287
+ --status-error-faint: rgba(239, 68, 68, 0.03);
288
+ --status-info-faint: rgba(59, 130, 246, 0.03);
289
+
290
+ /* Status — border (dark) */
291
+ --status-success-border: rgba(34, 197, 94, 0.20);
292
+ --status-warning-border: rgba(245, 158, 11, 0.20);
293
+ --status-error-border: rgba(239, 68, 68, 0.20);
294
+ --status-info-border: rgba(59, 130, 246, 0.20);
295
+
296
+ /* Collaboration (dark) */
297
+ --collab-primary: #a78bfa;
298
+ --collab-primary-muted: rgba(167, 139, 250, 0.10);
299
+ --collab-primary-subtle: rgba(167, 139, 250, 0.15);
300
+ --collab-primary-border: rgba(167, 139, 250, 0.20);
301
+
302
+ /* Voice (dark) */
303
+ --voice-recording: #fb7185;
304
+ --voice-recording-muted: rgba(251, 113, 133, 0.20);
305
+ --voice-processing: #22d3ee;
306
+ --voice-processing-muted: rgba(34, 211, 238, 0.15);
307
+
308
+ /* Banner / notifications (dark) */
309
+ --banner-primary: #818cf8;
310
+ --banner-primary-muted: rgba(129, 140, 248, 0.10);
311
+ --banner-primary-subtle: rgba(129, 140, 248, 0.15);
312
+ --banner-primary-border: rgba(129, 140, 248, 0.20);
313
+
314
+ /* Thinking gradients (dark) */
315
+ --gradient-thinking-high: linear-gradient(135deg, rgba(245, 158, 11, 0.20), rgba(239, 68, 68, 0.20));
316
+ --gradient-thinking-low: linear-gradient(135deg, rgba(99, 102, 241, 0.20), rgba(139, 92, 246, 0.20));
317
+
318
+ /* File type icons (dark — brighter variants) */
319
+ --file-icon-ts: #60a5fa;
320
+ --file-icon-js: #facc15;
321
+ --file-icon-json: #4ade80;
322
+ --file-icon-css: #818cf8;
323
+ --file-icon-rust: #fb923c;
324
+ --file-icon-markdown: #818cf8;
325
+
326
+ /* ── shadcn bridge (identical structure to :root — resolves
327
+ to dark Sero tokens defined above in this block) ────── */
328
+ --background: var(--bg-base);
329
+ --foreground: var(--text-primary);
330
+ --card: var(--bg-surface);
331
+ --card-foreground: var(--text-primary);
332
+ --popover: var(--bg-elevated);
333
+ --popover-foreground: var(--text-primary);
334
+ --primary: var(--text-primary);
335
+ --primary-foreground: var(--text-inverse);
336
+ --secondary: var(--bg-surface);
337
+ --secondary-foreground: var(--text-primary);
338
+ --muted: var(--bg-muted);
339
+ --muted-foreground: var(--text-muted);
340
+ --accent: var(--bg-overlay);
341
+ --accent-foreground: var(--text-primary);
342
+ --destructive: var(--status-error);
343
+ --border: var(--border-default);
344
+ --input: var(--border-subtle);
345
+ --ring: var(--border-focus);
346
+ --chart-1: oklch(0.488 0.243 264.376);
347
+ --chart-2: oklch(0.696 0.17 162.48);
348
+ --chart-3: oklch(0.769 0.188 70.08);
349
+ --chart-4: oklch(0.627 0.265 303.9);
350
+ --chart-5: oklch(0.645 0.246 16.439);
351
+ --sidebar: var(--bg-surface);
352
+ --sidebar-foreground: var(--text-primary);
353
+ --sidebar-primary: var(--accent-primary);
354
+ --sidebar-primary-foreground: var(--text-inverse);
355
+ --sidebar-accent: var(--bg-elevated);
356
+ --sidebar-accent-foreground: var(--text-primary);
357
+ --sidebar-border: var(--border-subtle);
358
+ --sidebar-ring: var(--border-focus);
359
+ }
360
+
361
+ html {
362
+ font-size: var(--font-size-base, 14px);
363
+ font-family: var(--font-sans);
364
+ }
365
+
366
+ @layer base {
367
+ * {
368
+ @apply border-border outline-ring/50;
369
+ }
370
+ body {
371
+ @apply bg-background text-foreground;
372
+ }
373
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "jsx": "react-jsx",
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "resolveJsonModule": true,
12
+ "isolatedModules": true,
13
+ "noEmit": true,
14
+ "lib": ["ES2023", "DOM", "DOM.Iterable"]
15
+ },
16
+ "include": ["src/**/*"],
17
+ "exclude": ["node_modules", "dist"]
18
+ }