@lastbrain/ai-ui-react 1.0.8 → 1.0.10

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.
@@ -1,77 +1,300 @@
1
1
  /**
2
2
  * Inline styles for AI UI components
3
- * These styles are injected directly to avoid CSS import requirements
3
+ * Theme: Purple/Violet primary color with light/dark mode support
4
4
  */
5
5
 
6
+ // Theme colors
7
+ const colors = {
8
+ // Purple/Violet theme
9
+ primary: "#8b5cf6",
10
+ primaryHover: "#7c3aed",
11
+ primaryLight: "#a78bfa",
12
+ primaryDark: "#6d28d9",
13
+
14
+ // Status colors
15
+ success: "#10b981",
16
+ successLight: "#34d399",
17
+ warning: "#f59e0b",
18
+ warningLight: "#fbbf24",
19
+ danger: "#ef4444",
20
+ dangerLight: "#f87171",
21
+
22
+ // Neutral colors - Light mode
23
+ light: {
24
+ bg: "#ffffff",
25
+ bgSecondary: "#f9fafb",
26
+ bgTertiary: "#f3f4f6",
27
+ border: "#e5e7eb",
28
+ borderLight: "#f3f4f6",
29
+ text: "#111827",
30
+ textSecondary: "#6b7280",
31
+ textTertiary: "#9ca3af",
32
+ shadow: "rgba(0, 0, 0, 0.1)",
33
+ shadowMd:
34
+ "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)",
35
+ shadowLg:
36
+ "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)",
37
+ shadowXl:
38
+ "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)",
39
+ },
40
+
41
+ // Neutral colors - Dark mode
42
+ dark: {
43
+ bg: "#1f2937",
44
+ bgSecondary: "#111827",
45
+ bgTertiary: "#0f172a",
46
+ border: "#374151",
47
+ borderLight: "#4b5563",
48
+ text: "#f9fafb",
49
+ textSecondary: "#d1d5db",
50
+ textTertiary: "#9ca3af",
51
+ shadow: "rgba(0, 0, 0, 0.3)",
52
+ shadowMd:
53
+ "0 4px 6px -1px rgba(0, 0, 0, 0.3), 0 2px 4px -2px rgba(0, 0, 0, 0.3)",
54
+ shadowLg:
55
+ "0 10px 15px -3px rgba(0, 0, 0, 0.3), 0 4px 6px -4px rgba(0, 0, 0, 0.3)",
56
+ shadowXl:
57
+ "0 20px 25px -5px rgba(0, 0, 0, 0.3), 0 8px 10px -6px rgba(0, 0, 0, 0.3)",
58
+ },
59
+ };
60
+
61
+ // Use light mode by default (can be made dynamic later)
62
+ const isDark =
63
+ typeof window !== "undefined" &&
64
+ window.matchMedia?.("(prefers-color-scheme: dark)").matches;
65
+ const theme = isDark ? colors.dark : colors.light;
66
+
6
67
  export const aiStyles = {
68
+ // Input field
69
+ input: {
70
+ width: "100%",
71
+ padding: "12px 40px 12px 16px",
72
+ fontSize: "14px",
73
+ lineHeight: "1.5",
74
+ color: theme.text,
75
+ background: theme.bg,
76
+ border: `1px solid ${theme.border}`,
77
+ borderRadius: "8px",
78
+ outline: "none",
79
+ transition: "all 0.2s",
80
+ fontFamily: "inherit",
81
+ } as React.CSSProperties,
82
+
83
+ inputFocus: {
84
+ borderColor: colors.primary,
85
+ boxShadow: `0 0 0 3px ${colors.primary}20`,
86
+ } as React.CSSProperties,
87
+
88
+ inputError: {
89
+ borderColor: colors.danger,
90
+ } as React.CSSProperties,
91
+
92
+ inputWrapper: {
93
+ position: "relative" as const,
94
+ width: "100%",
95
+ },
96
+
97
+ inputAiButton: {
98
+ position: "absolute" as const,
99
+ right: "8px",
100
+ top: "50%",
101
+ transform: "translateY(-50%)",
102
+ display: "flex",
103
+ alignItems: "center",
104
+ justifyContent: "center",
105
+ width: "32px",
106
+ height: "32px",
107
+ padding: "0",
108
+ border: "none",
109
+ borderRadius: "6px",
110
+ background: colors.primary,
111
+ color: "#ffffff",
112
+ cursor: "pointer",
113
+ transition: "all 0.2s",
114
+ boxShadow: theme.shadowMd,
115
+ } as React.CSSProperties,
116
+
117
+ inputAiButtonHover: {
118
+ background: colors.primaryHover,
119
+ boxShadow: theme.shadowLg,
120
+ transform: "translateY(-50%) scale(1.05)",
121
+ } as React.CSSProperties,
122
+
123
+ // Textarea
124
+ textarea: {
125
+ width: "100%",
126
+ minHeight: "120px",
127
+ padding: "12px 40px 12px 16px",
128
+ fontSize: "14px",
129
+ lineHeight: "1.5",
130
+ color: theme.text,
131
+ background: theme.bg,
132
+ border: `1px solid ${theme.border}`,
133
+ borderRadius: "8px",
134
+ outline: "none",
135
+ transition: "all 0.2s",
136
+ fontFamily: "inherit",
137
+ resize: "vertical" as const,
138
+ } as React.CSSProperties,
139
+
140
+ textareaFocus: {
141
+ borderColor: colors.primary,
142
+ boxShadow: `0 0 0 3px ${colors.primary}20`,
143
+ } as React.CSSProperties,
144
+
145
+ textareaWrapper: {
146
+ position: "relative" as const,
147
+ width: "100%",
148
+ },
149
+
150
+ textareaAiButton: {
151
+ position: "absolute" as const,
152
+ right: "8px",
153
+ top: "8px",
154
+ display: "flex",
155
+ alignItems: "center",
156
+ justifyContent: "center",
157
+ width: "32px",
158
+ height: "32px",
159
+ padding: "0",
160
+ border: "none",
161
+ borderRadius: "6px",
162
+ background: colors.primary,
163
+ color: "#ffffff",
164
+ cursor: "pointer",
165
+ transition: "all 0.2s",
166
+ boxShadow: theme.shadowMd,
167
+ } as React.CSSProperties,
168
+
169
+ textareaAiButtonHover: {
170
+ background: colors.primaryHover,
171
+ boxShadow: theme.shadowLg,
172
+ transform: "scale(1.05)",
173
+ } as React.CSSProperties,
174
+
175
+ // Button
176
+ button: {
177
+ display: "inline-flex" as const,
178
+ alignItems: "center" as const,
179
+ justifyContent: "center" as const,
180
+ gap: "8px",
181
+ padding: "10px 20px",
182
+ fontSize: "14px",
183
+ fontWeight: 500,
184
+ lineHeight: "1.5",
185
+ color: "#ffffff",
186
+ background: colors.primary,
187
+ border: "none",
188
+ borderRadius: "8px",
189
+ cursor: "pointer" as const,
190
+ transition: "all 0.2s",
191
+ boxShadow: theme.shadowMd,
192
+ fontFamily: "inherit",
193
+ } as React.CSSProperties,
194
+
195
+ buttonHover: {
196
+ background: colors.primaryHover,
197
+ boxShadow: theme.shadowLg,
198
+ transform: "translateY(-1px)",
199
+ } as React.CSSProperties,
200
+
201
+ buttonDisabled: {
202
+ opacity: 0.5,
203
+ cursor: "not-allowed" as const,
204
+ transform: "none",
205
+ } as React.CSSProperties,
206
+
207
+ // Select
208
+ select: {
209
+ width: "100%",
210
+ padding: "12px 16px",
211
+ fontSize: "14px",
212
+ lineHeight: "1.5",
213
+ color: theme.text,
214
+ background: theme.bg,
215
+ border: `1px solid ${theme.border}`,
216
+ borderRadius: "8px",
217
+ outline: "none",
218
+ transition: "all 0.2s",
219
+ fontFamily: "inherit",
220
+ cursor: "pointer" as const,
221
+ } as React.CSSProperties,
222
+
223
+ selectFocus: {
224
+ borderColor: colors.primary,
225
+ boxShadow: `0 0 0 3px ${colors.primary}20`,
226
+ } as React.CSSProperties,
227
+
228
+ // Status Button
7
229
  statusButton: {
8
230
  display: "inline-flex" as const,
9
231
  alignItems: "center" as const,
10
232
  justifyContent: "center" as const,
11
233
  width: "40px",
12
234
  height: "40px",
13
- border: "1px solid #e5e7eb",
235
+ border: `1px solid ${theme.border}`,
14
236
  borderRadius: "8px",
15
- background: "#ffffff",
16
- color: "#1f2937",
237
+ background: theme.bg,
238
+ color: theme.text,
17
239
  cursor: "pointer" as const,
18
240
  transition: "all 0.2s",
19
- },
241
+ boxShadow: theme.shadowMd,
242
+ } as React.CSSProperties,
20
243
 
21
244
  statusButtonHover: {
22
- background: "#f9fafb",
23
- boxShadow: "0 1px 3px 0 rgb(0 0 0 / 0.1)",
24
- },
245
+ background: theme.bgSecondary,
246
+ boxShadow: theme.shadowLg,
247
+ transform: "scale(1.05)",
248
+ } as React.CSSProperties,
25
249
 
26
250
  statusButtonDisabled: {
27
251
  opacity: 0.5,
28
252
  cursor: "not-allowed" as const,
29
- },
253
+ } as React.CSSProperties,
30
254
 
255
+ // Tooltip
31
256
  tooltip: {
32
257
  position: "absolute" as const,
33
- top: "calc(100% + 8px)",
34
- right: 0,
35
258
  zIndex: 1000,
36
259
  minWidth: "320px",
37
260
  maxWidth: "400px",
38
261
  padding: "16px",
39
- background: "#ffffff",
40
- border: "1px solid #e5e7eb",
41
- borderRadius: "8px",
42
- boxShadow:
43
- "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)",
262
+ background: theme.bg,
263
+ border: `1px solid ${theme.border}`,
264
+ borderRadius: "12px",
265
+ boxShadow: theme.shadowXl,
44
266
  fontSize: "12px",
45
- color: "#1f2937",
46
- },
267
+ color: theme.text,
268
+ pointerEvents: "auto" as const,
269
+ } as React.CSSProperties,
47
270
 
48
271
  tooltipHeader: {
49
272
  fontWeight: 600,
50
273
  fontSize: "16px",
51
274
  paddingBottom: "12px",
52
275
  marginBottom: "12px",
53
- borderBottom: "1px solid #e5e7eb",
54
- color: "#111827",
55
- },
276
+ borderBottom: `1px solid ${theme.borderLight}`,
277
+ color: theme.text,
278
+ } as React.CSSProperties,
56
279
 
57
280
  tooltipSection: {
58
281
  padding: "12px 0",
59
- borderTop: "1px solid #f3f4f6",
60
- },
282
+ borderTop: `1px solid ${theme.borderLight}`,
283
+ } as React.CSSProperties,
61
284
 
62
285
  tooltipSectionFirst: {
63
286
  borderTop: "none",
64
287
  paddingTop: 0,
65
- },
288
+ } as React.CSSProperties,
66
289
 
67
290
  tooltipSubtitle: {
68
291
  fontWeight: 600,
69
292
  marginBottom: "8px",
70
- fontSize: "12px",
71
- color: "#111827",
293
+ fontSize: "11px",
294
+ color: theme.textSecondary,
72
295
  textTransform: "uppercase" as const,
73
296
  letterSpacing: "0.05em",
74
- },
297
+ } as React.CSSProperties,
75
298
 
76
299
  tooltipRow: {
77
300
  display: "flex" as const,
@@ -79,35 +302,35 @@ export const aiStyles = {
79
302
  gap: "16px",
80
303
  marginBottom: "6px",
81
304
  alignItems: "center" as const,
82
- },
305
+ } as React.CSSProperties,
83
306
 
84
307
  tooltipLabel: {
85
- color: "#6b7280",
308
+ color: theme.textSecondary,
86
309
  fontSize: "12px",
87
- },
310
+ } as React.CSSProperties,
88
311
 
89
312
  tooltipValue: {
90
313
  fontFamily:
91
314
  'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
92
315
  fontSize: "12px",
93
- color: "#111827",
316
+ color: theme.text,
94
317
  fontWeight: 500,
95
- },
318
+ } as React.CSSProperties,
96
319
 
97
320
  tooltipValueBold: {
98
321
  fontWeight: 700,
99
- color: "#111827",
100
- },
322
+ color: theme.text,
323
+ } as React.CSSProperties,
101
324
 
102
325
  tooltipValueSuccess: {
103
- color: "#10b981",
326
+ color: colors.success,
104
327
  fontWeight: 600,
105
- },
328
+ } as React.CSSProperties,
106
329
 
107
330
  tooltipValueWarning: {
108
- color: "#f59e0b",
331
+ color: colors.warning,
109
332
  fontWeight: 600,
110
- },
333
+ } as React.CSSProperties,
111
334
 
112
335
  tooltipActions: {
113
336
  display: "flex" as const,
@@ -115,31 +338,165 @@ export const aiStyles = {
115
338
  justifyContent: "space-between" as const,
116
339
  paddingTop: "12px",
117
340
  marginTop: "8px",
118
- borderTop: "1px solid #f3f4f6",
119
- },
341
+ borderTop: `1px solid ${theme.borderLight}`,
342
+ } as React.CSSProperties,
120
343
 
121
344
  tooltipLink: {
122
345
  flex: 1,
123
346
  textAlign: "center" as const,
124
- padding: "6px 12px",
125
- color: "#3b82f6",
347
+ padding: "8px 12px",
348
+ color: colors.primary,
126
349
  textDecoration: "none",
127
350
  borderRadius: "6px",
128
351
  transition: "all 0.2s",
129
352
  fontSize: "11px",
130
353
  fontWeight: 500,
131
- background: "#eff6ff",
132
- border: "1px solid #dbeafe",
133
- },
354
+ background: `${colors.primary}10`,
355
+ border: `1px solid ${colors.primary}30`,
356
+ } as React.CSSProperties,
357
+
358
+ tooltipLinkHover: {
359
+ background: `${colors.primary}20`,
360
+ borderColor: colors.primary,
361
+ } as React.CSSProperties,
362
+
363
+ // Chip/Label
364
+ chip: {
365
+ display: "inline-flex" as const,
366
+ alignItems: "center" as const,
367
+ gap: "4px",
368
+ padding: "4px 12px",
369
+ fontSize: "12px",
370
+ fontWeight: 500,
371
+ borderRadius: "6px",
372
+ background: `${colors.primary}10`,
373
+ color: colors.primary,
374
+ border: `1px solid ${colors.primary}30`,
375
+ } as React.CSSProperties,
376
+
377
+ // Modal (basic styles)
378
+ modal: {
379
+ position: "fixed" as const,
380
+ top: 0,
381
+ left: 0,
382
+ right: 0,
383
+ bottom: 0,
384
+ zIndex: 9999,
385
+ display: "flex" as const,
386
+ alignItems: "center" as const,
387
+ justifyContent: "center" as const,
388
+ padding: "20px",
389
+ animation: "ai-fadeIn 0.2s ease-in",
390
+ } as React.CSSProperties,
391
+
392
+ modalOverlay: {
393
+ position: "absolute" as const,
394
+ top: 0,
395
+ left: 0,
396
+ right: 0,
397
+ bottom: 0,
398
+ background: "rgba(0, 0, 0, 0.5)",
399
+ backdropFilter: "blur(4px)",
400
+ WebkitBackdropFilter: "blur(4px)",
401
+ } as React.CSSProperties,
402
+
403
+ modalContent: {
404
+ position: "relative" as const,
405
+ width: "100%",
406
+ maxWidth: "600px",
407
+ maxHeight: "90vh",
408
+ overflow: "auto" as const,
409
+ background: theme.bg,
410
+ borderRadius: "12px",
411
+ boxShadow: theme.shadowXl,
412
+ padding: "0",
413
+ animation: "ai-slideUp 0.3s ease-out",
414
+ } as React.CSSProperties,
415
+
416
+ modalHeader: {
417
+ display: "flex" as const,
418
+ alignItems: "center" as const,
419
+ justifyContent: "space-between" as const,
420
+ padding: "20px 24px",
421
+ borderBottom: `1px solid ${theme.borderLight}`,
422
+ } as React.CSSProperties,
423
+
424
+ modalTitle: {
425
+ fontSize: "18px",
426
+ fontWeight: 600,
427
+ margin: 0,
428
+ color: theme.text,
429
+ } as React.CSSProperties,
134
430
 
431
+ modalCloseButton: {
432
+ display: "flex" as const,
433
+ alignItems: "center" as const,
434
+ justifyContent: "center" as const,
435
+ width: "32px",
436
+ height: "32px",
437
+ padding: "0",
438
+ border: "none",
439
+ borderRadius: "6px",
440
+ background: "transparent",
441
+ color: theme.textSecondary,
442
+ fontSize: "24px",
443
+ lineHeight: "1",
444
+ cursor: "pointer" as const,
445
+ transition: "all 0.2s",
446
+ } as React.CSSProperties,
447
+
448
+ modalCloseButtonHover: {
449
+ background: theme.bgSecondary,
450
+ color: theme.text,
451
+ } as React.CSSProperties,
452
+
453
+ modalBody: {
454
+ padding: "24px",
455
+ color: theme.textSecondary,
456
+ lineHeight: "1.6",
457
+ } as React.CSSProperties,
458
+
459
+ modalFooter: {
460
+ display: "flex" as const,
461
+ gap: "12px",
462
+ justifyContent: "flex-end" as const,
463
+ padding: "20px 24px",
464
+ borderTop: `1px solid ${theme.borderLight}`,
465
+ } as React.CSSProperties,
466
+
467
+ modalLabel: {
468
+ display: "block",
469
+ marginBottom: "8px",
470
+ fontSize: "14px",
471
+ fontWeight: 500,
472
+ color: theme.text,
473
+ } as React.CSSProperties,
474
+
475
+ modalInputGroup: {
476
+ marginBottom: "20px",
477
+ } as React.CSSProperties,
478
+
479
+ // Buttons variants
480
+ buttonSecondary: {
481
+ background: theme.bgSecondary,
482
+ color: theme.text,
483
+ border: `1px solid ${theme.border}`,
484
+ } as React.CSSProperties,
485
+
486
+ buttonSecondaryHover: {
487
+ background: theme.bgTertiary,
488
+ borderColor: theme.borderLight,
489
+ } as React.CSSProperties,
490
+
491
+ // Spinner
135
492
  spinner: {
136
493
  width: "16px",
137
494
  height: "16px",
138
- border: "2px solid #e5e7eb",
139
- borderTopColor: "#3b82f6",
495
+ border: "2px solid transparent",
496
+ borderTopColor: "currentColor",
140
497
  borderRadius: "50%",
141
- animation: "spin 1s linear infinite",
142
- },
498
+ animation: "ai-spin 1s linear infinite",
499
+ } as React.CSSProperties,
143
500
  };
144
501
 
145
502
  // Inject keyframes animation for spinner
@@ -150,6 +507,81 @@ if (typeof document !== "undefined") {
150
507
  from { transform: rotate(0deg); }
151
508
  to { transform: rotate(360deg); }
152
509
  }
510
+
511
+ @keyframes ai-fadeIn {
512
+ from { opacity: 0; }
513
+ to { opacity: 1; }
514
+ }
515
+
516
+ @keyframes ai-slideUp {
517
+ from {
518
+ opacity: 0;
519
+ transform: translateY(20px);
520
+ }
521
+ to {
522
+ opacity: 1;
523
+ transform: translateY(0);
524
+ }
525
+ }
153
526
  `;
154
527
  document.head.appendChild(styleSheet);
155
528
  }
529
+
530
+ // Helper function to calculate tooltip position
531
+ export function calculateTooltipPosition(
532
+ buttonRect: DOMRect,
533
+ tooltipWidth: number = 350,
534
+ tooltipHeight: number = 500
535
+ ): { top?: string; bottom?: string; left?: string; right?: string } {
536
+ const viewportWidth = window.innerWidth;
537
+ const viewportHeight = window.innerHeight;
538
+ const margin = 8;
539
+
540
+ const position: {
541
+ top?: string;
542
+ bottom?: string;
543
+ left?: string;
544
+ right?: string;
545
+ } = {};
546
+
547
+ // Vertical positioning
548
+ const spaceBelow = viewportHeight - buttonRect.bottom;
549
+ const spaceAbove = buttonRect.top;
550
+
551
+ if (spaceBelow >= tooltipHeight + margin) {
552
+ // Show below
553
+ position.top = `calc(100% + ${margin}px)`;
554
+ } else if (spaceAbove >= tooltipHeight + margin) {
555
+ // Show above
556
+ position.bottom = `calc(100% + ${margin}px)`;
557
+ } else {
558
+ // Show below anyway (scrollable)
559
+ position.top = `calc(100% + ${margin}px)`;
560
+ }
561
+
562
+ // Horizontal positioning
563
+ const spaceRight = viewportWidth - buttonRect.right;
564
+ const spaceLeft = buttonRect.left;
565
+
566
+ if (spaceRight >= tooltipWidth + margin) {
567
+ // Align to right edge of button
568
+ position.right = "0";
569
+ } else if (spaceLeft >= tooltipWidth + margin) {
570
+ // Align to left edge of button
571
+ position.left = "0";
572
+ } else {
573
+ // Center, but ensure it doesn't go off-screen
574
+ const centerOffset = (buttonRect.width - tooltipWidth) / 2;
575
+ const leftPosition = buttonRect.left + centerOffset;
576
+
577
+ if (leftPosition < margin) {
578
+ position.left = `${margin - buttonRect.left}px`;
579
+ } else if (leftPosition + tooltipWidth > viewportWidth - margin) {
580
+ position.right = `${margin}px`;
581
+ } else {
582
+ position.right = "0";
583
+ }
584
+ }
585
+
586
+ return position;
587
+ }