@timbal-ai/timbal-react 0.3.0 → 0.5.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.
package/dist/styles.css CHANGED
@@ -1,46 +1,313 @@
1
1
  /*
2
- * Optional companion styles for `@timbal-ai/timbal-react`.
2
+ * Complete companion stylesheet for `@timbal-ai/timbal-react`.
3
3
  *
4
- * Import this once from your app entry to get the polished defaults that
5
- * the blueprint used inline:
4
+ * Import this once from your app entry to get a fully working theme:
6
5
  *
7
6
  * import "@timbal-ai/timbal-react/styles.css";
8
7
  *
9
- * Tailwind v4 is required for the design tokens (`var(--primary)`, etc.).
10
- * The package itself ships no bundled CSS — you can drop this file entirely
11
- * and ship your own.
8
+ * The package's components are written exclusively against semantic Tailwind
9
+ * tokens (bg-card, text-foreground, border-border, bg-elevated-from/to,
10
+ * shadow-card, …). Every token has a complete light + dark definition here
11
+ * so a consumer's host CSS only needs:
12
+ *
13
+ * @import "tailwindcss";
14
+ * @source "../node_modules/@timbal-ai/timbal-react/dist";
15
+ *
16
+ * Apps that want their own palette can override any --foo / --color-foo
17
+ * variable from their own :root / .dark rules — these rules cascade
18
+ * normally over the ones declared here.
12
19
  */
13
20
 
14
- /* ── AI breathing icon (welcome screen) ── */
15
- @keyframes timbal-ai-breathe {
16
- 0%, 100% { transform: scale(1); opacity: 0.72; }
17
- 50% { transform: scale(1.1); opacity: 1; }
18
- }
21
+ /* =============================================================== *
22
+ * Base tokens — shadcn-style :root / .dark pairs *
23
+ * =============================================================== */
19
24
 
20
- @keyframes timbal-ai-ring-glow {
21
- 0%, 100% { opacity: 1; }
22
- 50% { opacity: 0.55; }
23
- }
25
+ :root {
26
+ --radius: 0.75rem;
24
27
 
25
- @keyframes timbal-ai-pulse-ring {
26
- 0% { box-shadow: 0 0 0 0 oklch(from var(--primary, #6366f1) l c h / 0.18); }
27
- 65% { box-shadow: 0 0 0 8px oklch(from var(--primary, #6366f1) l c h / 0); }
28
- 100% { box-shadow: 0 0 0 0 oklch(from var(--primary, #6366f1) l c h / 0); }
29
- }
28
+ /* Studio light — matches the Timbal Platform HeroUI light theme */
29
+ --background: oklch(0.995 0 0);
30
+ --foreground: oklch(0.145 0 0);
31
+ --card: oklch(0.995 0 0);
32
+ --card-foreground: oklch(0.145 0 0);
33
+ --popover: oklch(0.995 0 0);
34
+ --popover-foreground: oklch(0.145 0 0);
35
+ --primary: oklch(0.205 0 0);
36
+ --primary-foreground: oklch(0.985 0 0);
37
+ --secondary: oklch(0.975 0.002 260);
38
+ --secondary-foreground: oklch(0.205 0 0);
39
+ --muted: oklch(0.975 0.002 260);
40
+ --muted-foreground: oklch(0.52 0.014 260);
41
+ --accent: oklch(0.965 0.002 260);
42
+ --accent-foreground: oklch(0.205 0 0);
43
+ --destructive: oklch(0.577 0.245 27.325);
44
+ --destructive-foreground: oklch(0.985 0 0);
45
+ --border: oklch(0.91 0.004 260);
46
+ --input: oklch(0.91 0.004 260);
47
+ --ring: oklch(0.55 0.014 260);
48
+
49
+ /* Sidebar scope — used by StudioSidebar */
50
+ --sidebar: oklch(0.985 0 0);
51
+ --sidebar-foreground: oklch(0.145 0 0);
52
+ --sidebar-primary: oklch(0.205 0 0);
53
+ --sidebar-primary-foreground: oklch(0.985 0 0);
54
+ --sidebar-accent: oklch(0.975 0.002 260);
55
+ --sidebar-accent-foreground: oklch(0.205 0 0);
56
+ --sidebar-border: oklch(0.91 0.004 260);
57
+ --sidebar-ring: oklch(0.55 0.014 260);
58
+
59
+ /* Timbal extension tokens — keep light + dark in sync below */
60
+
61
+ /* Elevated surface gradient (cards, sidebar panel, secondary chrome). */
62
+ --elevated-from: oklch(1 0 0);
63
+ --elevated-to: oklch(0.985 0.002 260 / 0.7);
64
+
65
+ /* Soft playground gradient behind the message column. */
66
+ --playground-from: oklch(0.91 0.004 260 / 0.6);
67
+ --playground-via: oklch(0.965 0.002 260 / 0.3);
68
+ --playground-to: var(--background);
69
+
70
+ /* Composer shell — opaque card with stronger focus border. */
71
+ --composer-bg: oklch(1 0 0);
72
+ --composer-border: oklch(0.91 0.004 260 / 0.6);
73
+ --composer-border-focus: oklch(0.62 0.005 260 / 0.8);
74
+
75
+ /* User message bubble — neutral-200 on light, neutral-700 on dark. */
76
+ --bubble-user: oklch(0.922 0 0);
77
+ --bubble-user-foreground: oklch(0.145 0 0);
78
+
79
+ /* Primary button gradient endpoints — inverts in dark mode. */
80
+ --primary-fill-from: oklch(0.27 0 0);
81
+ --primary-fill-to: oklch(0 0 0);
82
+ --primary-fill-hover-from: oklch(0.32 0 0);
83
+ --primary-fill-hover-to: oklch(0.17 0 0);
84
+ --primary-fill-active-from: oklch(0 0 0);
85
+ --primary-fill-active-to: oklch(0 0 0);
86
+
87
+ /* Secondary button gradient endpoints. */
88
+ --secondary-fill-hover-from: oklch(0.985 0.002 260 / 0.5);
89
+ --secondary-fill-hover-to: oklch(0.965 0.002 260 / 0.65);
90
+ --secondary-fill-active-from: oklch(0.965 0.002 260 / 0.7);
91
+ --secondary-fill-active-to: oklch(0.91 0.004 260 / 0.65);
30
92
 
31
- .animate-ai-breathe {
32
- animation: timbal-ai-breathe 3.2s ease-in-out infinite;
93
+ /* Destructive button gradient endpoints. */
94
+ --destructive-fill-hover-from: oklch(0.97 0.06 27 / 0.9);
95
+ --destructive-fill-hover-to: oklch(0.93 0.09 27 / 0.7);
96
+ --destructive-fill-active-from: oklch(0.93 0.09 27 / 0.9);
97
+ --destructive-fill-active-to: oklch(0.86 0.13 27 / 0.65);
98
+
99
+ /* Ghost button hover/active fills. */
100
+ --ghost-fill-hover: oklch(0.965 0.002 260 / 0.7);
101
+ --ghost-fill-active: oklch(0.91 0.004 260 / 0.7);
102
+
103
+ /* Code block surface (markdown). */
104
+ --code-block-bg: oklch(0.98 0 0);
105
+ --code-header-bg: oklch(0.965 0 0);
106
+
107
+ /* Math (KaTeX) display surface. */
108
+ --katex-bg: oklch(0.97 0 0 / 0.6);
109
+ --katex-border: oklch(0.922 0 0);
110
+
111
+ /* Markdown table zebra. */
112
+ --md-table-zebra: oklch(0.97 0 0 / 0.4);
113
+
114
+ /* Scrollbar thumb (light & dark share oklch base, only alpha changes). */
115
+ --scrollbar-thumb: oklch(0.708 0 0 / 0.3);
116
+ --scrollbar-thumb-hover: oklch(0.708 0 0 / 0.5);
117
+
118
+ /* Card shadows. */
119
+ --shadow-card-value: 0 1px 2px -0.5px rgba(0, 0, 0, 0.05);
120
+ --shadow-card-elevated-value: 0 4px 24px rgba(0, 0, 0, 0.06);
121
+
122
+ /* Studio layout (used by StudioSidebar / TimbalStudioShell). */
123
+ --studio-topbar-gap: 0.5rem;
124
+ --studio-topbar-height: 3rem;
125
+ --studio-chrome-pill-height: 2.5rem;
126
+ --studio-inset-top: calc(var(--studio-topbar-gap) + var(--studio-topbar-height));
127
+ --studio-sidebar-gap: 0.75rem;
128
+ --studio-sidebar-width: 14rem;
129
+ --studio-sidebar-width-collapsed: 3.25rem;
130
+ --studio-sidebar-content-gap: 0.5rem;
131
+ --studio-inset-left: calc(
132
+ var(--studio-sidebar-gap) + var(--studio-sidebar-width) +
133
+ var(--studio-sidebar-content-gap)
134
+ );
135
+ --studio-inset-left-collapsed: calc(
136
+ var(--studio-sidebar-gap) + var(--studio-sidebar-width-collapsed) +
137
+ var(--studio-sidebar-content-gap)
138
+ );
33
139
  }
34
140
 
35
- .animate-ai-ring-glow {
36
- animation: timbal-ai-ring-glow 3.2s ease-in-out infinite;
141
+ .dark {
142
+ --background: oklch(0.145 0 0);
143
+ --foreground: oklch(0.985 0 0);
144
+ --card: oklch(0.19 0.005 260);
145
+ --card-foreground: oklch(0.985 0 0);
146
+ --popover: oklch(0.19 0.005 260);
147
+ --popover-foreground: oklch(0.985 0 0);
148
+ --primary: oklch(0.985 0 0);
149
+ --primary-foreground: oklch(0.205 0 0);
150
+ --secondary: oklch(0.22 0.005 260);
151
+ --secondary-foreground: oklch(0.985 0 0);
152
+ --muted: oklch(0.22 0.005 260);
153
+ --muted-foreground: oklch(0.72 0.01 260);
154
+ --accent: oklch(0.25 0.008 260);
155
+ --accent-foreground: oklch(0.985 0 0);
156
+ --destructive: oklch(0.704 0.191 22.216);
157
+ --destructive-foreground: oklch(0.985 0 0);
158
+ --border: oklch(1 0 0 / 0.10);
159
+ --input: oklch(1 0 0 / 0.12);
160
+ --ring: oklch(0.55 0.01 260);
161
+
162
+ --sidebar: oklch(0.19 0.005 260);
163
+ --sidebar-foreground: oklch(0.985 0 0);
164
+ --sidebar-primary: oklch(0.985 0 0);
165
+ --sidebar-primary-foreground: oklch(0.205 0 0);
166
+ --sidebar-accent: oklch(0.25 0.008 260);
167
+ --sidebar-accent-foreground: oklch(0.985 0 0);
168
+ --sidebar-border: oklch(1 0 0 / 0.10);
169
+ --sidebar-ring: oklch(0.55 0.01 260);
170
+
171
+ --elevated-from: oklch(1 0 0 / 0.05);
172
+ --elevated-to: oklch(1 0 0 / 0.025);
173
+
174
+ --playground-from: oklch(0.27 0.005 285);
175
+ --playground-via: oklch(0.19 0.005 260);
176
+ --playground-to: oklch(0.13 0.005 285);
177
+
178
+ --composer-bg: oklch(0.19 0.005 260);
179
+ --composer-border: oklch(1 0 0 / 0.12);
180
+ --composer-border-focus: oklch(1 0 0 / 0.22);
181
+
182
+ --bubble-user: oklch(0.371 0 0);
183
+ --bubble-user-foreground: oklch(0.985 0 0);
184
+
185
+ /* Primary inverts on dark — light gradient on a dark background. */
186
+ --primary-fill-from: oklch(1 0 0);
187
+ --primary-fill-to: oklch(0.92 0 0);
188
+ --primary-fill-hover-from: oklch(1 0 0);
189
+ --primary-fill-hover-to: oklch(0.97 0 0);
190
+ --primary-fill-active-from: oklch(0.92 0 0);
191
+ --primary-fill-active-to: oklch(0.78 0 0);
192
+
193
+ --secondary-fill-hover-from: oklch(1 0 0 / 0.07);
194
+ --secondary-fill-hover-to: oklch(1 0 0 / 0.045);
195
+ --secondary-fill-active-from: oklch(1 0 0 / 0.10);
196
+ --secondary-fill-active-to: oklch(1 0 0 / 0.07);
197
+
198
+ --destructive-fill-hover-from: oklch(0.6 0.2 27 / 0.12);
199
+ --destructive-fill-hover-to: oklch(0.6 0.2 27 / 0.08);
200
+ --destructive-fill-active-from: oklch(0.6 0.2 27 / 0.20);
201
+ --destructive-fill-active-to: oklch(0.6 0.2 27 / 0.12);
202
+
203
+ --ghost-fill-hover: oklch(1 0 0 / 0.10);
204
+ --ghost-fill-active: oklch(1 0 0 / 0.15);
205
+
206
+ --code-block-bg: oklch(0.19 0 0);
207
+ --code-header-bg: oklch(0.22 0 0 / 0.8);
208
+
209
+ --katex-bg: oklch(0.2 0 0 / 0.5);
210
+ --katex-border: oklch(1 0 0 / 0.08);
211
+
212
+ --md-table-zebra: oklch(0.2 0 0 / 0.3);
213
+
214
+ --scrollbar-thumb: oklch(0.708 0 0 / 0.4);
215
+ --scrollbar-thumb-hover: oklch(0.708 0 0 / 0.6);
216
+
217
+ --shadow-card-value: 0 1px 3px rgba(0, 0, 0, 0.22);
218
+ --shadow-card-elevated-value: 0 4px 24px rgba(0, 0, 0, 0.35);
37
219
  }
38
220
 
39
- .animate-ai-pulse-ring {
40
- animation: timbal-ai-pulse-ring 3.2s ease-in-out infinite;
41
- border-radius: var(--radius-xl, 12px);
221
+ /* =============================================================== *
222
+ * Tailwind v4 @theme inline — re-aliases the base tokens above so *
223
+ * `bg-background`, `text-foreground`, `border-border`, etc. all *
224
+ * resolve via var() and flip with .dark. *
225
+ * =============================================================== */
226
+
227
+ @theme inline {
228
+ --radius-sm: calc(var(--radius) - 4px);
229
+ --radius-md: calc(var(--radius) - 2px);
230
+ --radius-lg: var(--radius);
231
+ --radius-xl: calc(var(--radius) + 4px);
232
+
233
+ --color-background: var(--background);
234
+ --color-foreground: var(--foreground);
235
+ --color-card: var(--card);
236
+ --color-card-foreground: var(--card-foreground);
237
+ --color-popover: var(--popover);
238
+ --color-popover-foreground: var(--popover-foreground);
239
+ --color-primary: var(--primary);
240
+ --color-primary-foreground: var(--primary-foreground);
241
+ --color-secondary: var(--secondary);
242
+ --color-secondary-foreground: var(--secondary-foreground);
243
+ --color-muted: var(--muted);
244
+ --color-muted-foreground: var(--muted-foreground);
245
+ --color-accent: var(--accent);
246
+ --color-accent-foreground: var(--accent-foreground);
247
+ --color-destructive: var(--destructive);
248
+ --color-destructive-foreground: var(--destructive-foreground);
249
+ --color-border: var(--border);
250
+ --color-input: var(--input);
251
+ --color-ring: var(--ring);
252
+
253
+ --color-sidebar: var(--sidebar);
254
+ --color-sidebar-foreground: var(--sidebar-foreground);
255
+ --color-sidebar-primary: var(--sidebar-primary);
256
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
257
+ --color-sidebar-accent: var(--sidebar-accent);
258
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
259
+ --color-sidebar-border: var(--sidebar-border);
260
+ --color-sidebar-ring: var(--sidebar-ring);
261
+
262
+ /* Timbal extensions — exposed as colour tokens so they work with
263
+ bg-*, border-*, text-*, from-*, via-*, to-* utilities alike. */
264
+ --color-elevated-from: var(--elevated-from);
265
+ --color-elevated-to: var(--elevated-to);
266
+ --color-playground-from: var(--playground-from);
267
+ --color-playground-via: var(--playground-via);
268
+ --color-playground-to: var(--playground-to);
269
+ --color-composer-bg: var(--composer-bg);
270
+ --color-composer-border: var(--composer-border);
271
+ --color-composer-border-focus: var(--composer-border-focus);
272
+ --color-bubble-user: var(--bubble-user);
273
+ --color-bubble-user-foreground: var(--bubble-user-foreground);
274
+
275
+ --color-primary-fill-from: var(--primary-fill-from);
276
+ --color-primary-fill-to: var(--primary-fill-to);
277
+ --color-primary-fill-hover-from: var(--primary-fill-hover-from);
278
+ --color-primary-fill-hover-to: var(--primary-fill-hover-to);
279
+ --color-primary-fill-active-from: var(--primary-fill-active-from);
280
+ --color-primary-fill-active-to: var(--primary-fill-active-to);
281
+
282
+ --color-secondary-fill-hover-from: var(--secondary-fill-hover-from);
283
+ --color-secondary-fill-hover-to: var(--secondary-fill-hover-to);
284
+ --color-secondary-fill-active-from: var(--secondary-fill-active-from);
285
+ --color-secondary-fill-active-to: var(--secondary-fill-active-to);
286
+
287
+ --color-destructive-fill-hover-from: var(--destructive-fill-hover-from);
288
+ --color-destructive-fill-hover-to: var(--destructive-fill-hover-to);
289
+ --color-destructive-fill-active-from: var(--destructive-fill-active-from);
290
+ --color-destructive-fill-active-to: var(--destructive-fill-active-to);
291
+
292
+ --color-ghost-fill-hover: var(--ghost-fill-hover);
293
+ --color-ghost-fill-active: var(--ghost-fill-active);
294
+
295
+ --color-code-block-bg: var(--code-block-bg);
296
+ --color-code-header-bg: var(--code-header-bg);
297
+
298
+ --shadow-card: var(--shadow-card-value);
299
+ --shadow-card-elevated: var(--shadow-card-elevated-value);
42
300
  }
43
301
 
302
+ /* Allow the `dark` Tailwind variant to be triggered by an ancestor `.dark`
303
+ class. Apps using next-themes / a manual toggle just add/remove `.dark`
304
+ from `<html>` and every utility flips together with the base tokens. */
305
+ @custom-variant dark (&:is(.dark *));
306
+
307
+ /* =============================================================== *
308
+ * Polish — markdown, shiki, katex, scrollbars *
309
+ * =============================================================== */
310
+
44
311
  /* ── Markdown inline code ── */
45
312
  .dark code:not(pre code) {
46
313
  background-color: oklch(0.269 0 0 / 0.8);
@@ -48,14 +315,14 @@
48
315
 
49
316
  /* ── Shiki dual-theme support ── */
50
317
  .shiki-wrapper pre {
51
- background: var(--shiki-light-bg, oklch(0.98 0 0)) !important;
318
+ background: var(--shiki-light-bg, var(--code-block-bg)) !important;
52
319
  }
53
320
  .shiki-wrapper code,
54
321
  .shiki-wrapper code span {
55
322
  color: var(--shiki-light, inherit);
56
323
  }
57
324
  .dark .shiki-wrapper pre {
58
- background: var(--shiki-dark-bg, oklch(0.13 0 0)) !important;
325
+ background: var(--shiki-dark-bg, var(--code-block-bg)) !important;
59
326
  }
60
327
  .dark .shiki-wrapper code,
61
328
  .dark .shiki-wrapper code span {
@@ -85,16 +352,12 @@
85
352
  .katex-display {
86
353
  margin: 1.25rem 0 !important;
87
354
  padding: 1rem 1.25rem;
88
- background: oklch(0.97 0 0 / 0.6);
89
- border: 1px solid oklch(0.922 0 0);
355
+ background: var(--katex-bg);
356
+ border: 1px solid var(--katex-border);
90
357
  border-radius: 0.5rem;
91
358
  overflow-x: auto;
92
359
  overflow-y: hidden;
93
360
  }
94
- .dark .katex-display {
95
- background: oklch(0.2 0 0 / 0.5);
96
- border-color: oklch(1 0 0 / 0.08);
97
- }
98
361
  .katex-display > .katex {
99
362
  text-align: center;
100
363
  }
@@ -110,10 +373,7 @@
110
373
 
111
374
  /* ── Markdown table zebra striping ── */
112
375
  .aui-md-table tbody tr:nth-child(even) {
113
- background: oklch(0.97 0 0 / 0.4);
114
- }
115
- .dark .aui-md-table tbody tr:nth-child(even) {
116
- background: oklch(0.2 0 0 / 0.3);
376
+ background: var(--md-table-zebra);
117
377
  }
118
378
 
119
379
  /* ── Code header polish ── */
@@ -170,7 +430,7 @@
170
430
  .aui-thread-root,
171
431
  .aui-thread-root * {
172
432
  scrollbar-width: thin;
173
- scrollbar-color: oklch(0.708 0 0 / 0.3) transparent;
433
+ scrollbar-color: var(--scrollbar-thumb) transparent;
174
434
  }
175
435
 
176
436
  .aui-thread-root *::-webkit-scrollbar {
@@ -184,7 +444,7 @@
184
444
  }
185
445
 
186
446
  .aui-thread-root *::-webkit-scrollbar-thumb {
187
- background: oklch(0.708 0 0 / 0.3);
447
+ background: var(--scrollbar-thumb);
188
448
  border-radius: 4px;
189
449
  border: 2px solid transparent;
190
450
  background-clip: content-box;
@@ -192,19 +452,19 @@
192
452
  }
193
453
 
194
454
  .aui-thread-root *::-webkit-scrollbar-thumb:hover {
195
- background: oklch(0.708 0 0 / 0.5);
455
+ background: var(--scrollbar-thumb-hover);
196
456
  background-clip: content-box;
197
457
  }
198
458
 
199
- .dark .aui-thread-root,
200
- .dark .aui-thread-root * {
201
- scrollbar-color: oklch(0.708 0 0 / 0.4) transparent;
202
- }
203
-
204
- .dark .aui-thread-root *::-webkit-scrollbar-thumb {
205
- background: oklch(0.708 0 0 / 0.4);
206
- }
459
+ /* =============================================================== *
460
+ * Component fixes — baked in so consumers don't need overrides *
461
+ * =============================================================== */
207
462
 
208
- .dark .aui-thread-root *::-webkit-scrollbar-thumb:hover {
209
- background: oklch(0.708 0 0 / 0.6);
463
+ /* The thread viewport footer no longer paints its own background. The
464
+ thread root already paints bg-background, so the sticky footer must
465
+ stay transparent — otherwise a token mismatch surfaces as a coloured
466
+ strip behind the composer. */
467
+ .aui-thread-viewport-footer {
468
+ background: transparent !important;
469
+ border-radius: 0 !important;
210
470
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@timbal-ai/timbal-react",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "React components and runtime for building Timbal chat UIs",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -36,6 +36,7 @@
36
36
  },
37
37
  "dependencies": {
38
38
  "@assistant-ui/react-markdown": "^0.12.3",
39
+ "@paper-design/shaders-react": "^0.0.76",
39
40
  "@radix-ui/react-avatar": "^1.1.11",
40
41
  "@radix-ui/react-dialog": "^1.1.15",
41
42
  "@radix-ui/react-slot": "^1.2.4",