@lastbrain/ai-ui-react 1.0.7 → 1.0.9

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.
@@ -0,0 +1,587 @@
1
+ /**
2
+ * Inline styles for AI UI components
3
+ * Theme: Purple/Violet primary color with light/dark mode support
4
+ */
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
+
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
229
+ statusButton: {
230
+ display: "inline-flex" as const,
231
+ alignItems: "center" as const,
232
+ justifyContent: "center" as const,
233
+ width: "40px",
234
+ height: "40px",
235
+ border: `1px solid ${theme.border}`,
236
+ borderRadius: "8px",
237
+ background: theme.bg,
238
+ color: theme.text,
239
+ cursor: "pointer" as const,
240
+ transition: "all 0.2s",
241
+ boxShadow: theme.shadowMd,
242
+ } as React.CSSProperties,
243
+
244
+ statusButtonHover: {
245
+ background: theme.bgSecondary,
246
+ boxShadow: theme.shadowLg,
247
+ transform: "scale(1.05)",
248
+ } as React.CSSProperties,
249
+
250
+ statusButtonDisabled: {
251
+ opacity: 0.5,
252
+ cursor: "not-allowed" as const,
253
+ } as React.CSSProperties,
254
+
255
+ // Tooltip
256
+ tooltip: {
257
+ position: "absolute" as const,
258
+ zIndex: 1000,
259
+ minWidth: "320px",
260
+ maxWidth: "400px",
261
+ padding: "16px",
262
+ background: theme.bg,
263
+ border: `1px solid ${theme.border}`,
264
+ borderRadius: "12px",
265
+ boxShadow: theme.shadowXl,
266
+ fontSize: "12px",
267
+ color: theme.text,
268
+ pointerEvents: "auto" as const,
269
+ } as React.CSSProperties,
270
+
271
+ tooltipHeader: {
272
+ fontWeight: 600,
273
+ fontSize: "16px",
274
+ paddingBottom: "12px",
275
+ marginBottom: "12px",
276
+ borderBottom: `1px solid ${theme.borderLight}`,
277
+ color: theme.text,
278
+ } as React.CSSProperties,
279
+
280
+ tooltipSection: {
281
+ padding: "12px 0",
282
+ borderTop: `1px solid ${theme.borderLight}`,
283
+ } as React.CSSProperties,
284
+
285
+ tooltipSectionFirst: {
286
+ borderTop: "none",
287
+ paddingTop: 0,
288
+ } as React.CSSProperties,
289
+
290
+ tooltipSubtitle: {
291
+ fontWeight: 600,
292
+ marginBottom: "8px",
293
+ fontSize: "11px",
294
+ color: theme.textSecondary,
295
+ textTransform: "uppercase" as const,
296
+ letterSpacing: "0.05em",
297
+ } as React.CSSProperties,
298
+
299
+ tooltipRow: {
300
+ display: "flex" as const,
301
+ justifyContent: "space-between" as const,
302
+ gap: "16px",
303
+ marginBottom: "6px",
304
+ alignItems: "center" as const,
305
+ } as React.CSSProperties,
306
+
307
+ tooltipLabel: {
308
+ color: theme.textSecondary,
309
+ fontSize: "12px",
310
+ } as React.CSSProperties,
311
+
312
+ tooltipValue: {
313
+ fontFamily:
314
+ 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
315
+ fontSize: "12px",
316
+ color: theme.text,
317
+ fontWeight: 500,
318
+ } as React.CSSProperties,
319
+
320
+ tooltipValueBold: {
321
+ fontWeight: 700,
322
+ color: theme.text,
323
+ } as React.CSSProperties,
324
+
325
+ tooltipValueSuccess: {
326
+ color: colors.success,
327
+ fontWeight: 600,
328
+ } as React.CSSProperties,
329
+
330
+ tooltipValueWarning: {
331
+ color: colors.warning,
332
+ fontWeight: 600,
333
+ } as React.CSSProperties,
334
+
335
+ tooltipActions: {
336
+ display: "flex" as const,
337
+ gap: "8px",
338
+ justifyContent: "space-between" as const,
339
+ paddingTop: "12px",
340
+ marginTop: "8px",
341
+ borderTop: `1px solid ${theme.borderLight}`,
342
+ } as React.CSSProperties,
343
+
344
+ tooltipLink: {
345
+ flex: 1,
346
+ textAlign: "center" as const,
347
+ padding: "8px 12px",
348
+ color: colors.primary,
349
+ textDecoration: "none",
350
+ borderRadius: "6px",
351
+ transition: "all 0.2s",
352
+ fontSize: "11px",
353
+ fontWeight: 500,
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,
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
492
+ spinner: {
493
+ width: "16px",
494
+ height: "16px",
495
+ border: "2px solid transparent",
496
+ borderTopColor: "currentColor",
497
+ borderRadius: "50%",
498
+ animation: "ai-spin 1s linear infinite",
499
+ } as React.CSSProperties,
500
+ };
501
+
502
+ // Inject keyframes animation for spinner
503
+ if (typeof document !== "undefined") {
504
+ const styleSheet = document.createElement("style");
505
+ styleSheet.textContent = `
506
+ @keyframes ai-spin {
507
+ from { transform: rotate(0deg); }
508
+ to { transform: rotate(360deg); }
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
+ }
526
+ `;
527
+ document.head.appendChild(styleSheet);
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
+ }