reactbridge-sdk 0.1.15 → 0.1.17
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/components/ReactBridgeChatbox.d.ts.map +1 -1
- package/dist/components/ReactBridgeSearch.d.ts.map +1 -1
- package/dist/hooks/useReactBridge.d.ts.map +1 -1
- package/dist/index.esm.js +637 -37
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +637 -37
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +8 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/api.d.ts +3 -0
- package/dist/utils/api.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -60,12 +60,50 @@ class ReactBridgeAPI {
|
|
|
60
60
|
timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
|
+
// Check if this is a multimodal request (has image or document)
|
|
64
|
+
const hasFile = request.image || request.document;
|
|
65
|
+
let headers = Object.assign({ 'X-API-Key': this.config.apiKey }, this.config.headers);
|
|
66
|
+
let body;
|
|
67
|
+
if (hasFile) {
|
|
68
|
+
// Use FormData for file uploads
|
|
69
|
+
const formData = new FormData();
|
|
70
|
+
// Add text fields
|
|
71
|
+
formData.append('userId', request.userId);
|
|
72
|
+
formData.append('query', request.query);
|
|
73
|
+
if (request.userName)
|
|
74
|
+
formData.append('userName', request.userName);
|
|
75
|
+
if (request.userPreferences)
|
|
76
|
+
formData.append('userPreferences', request.userPreferences);
|
|
77
|
+
if (request.userRecentActivity)
|
|
78
|
+
formData.append('userRecentActivity', request.userRecentActivity);
|
|
79
|
+
if (request.interfaceState)
|
|
80
|
+
formData.append('interfaceState', JSON.stringify(request.interfaceState));
|
|
81
|
+
if (request.sessionId)
|
|
82
|
+
formData.append('sessionId', request.sessionId);
|
|
83
|
+
if (request.modalityHint)
|
|
84
|
+
formData.append('modalityHint', request.modalityHint);
|
|
85
|
+
// Add files
|
|
86
|
+
if (request.image)
|
|
87
|
+
formData.append('image', request.image);
|
|
88
|
+
if (request.document)
|
|
89
|
+
formData.append('document', request.document);
|
|
90
|
+
body = formData;
|
|
91
|
+
// Don't set Content-Type for FormData - let browser set it with boundary
|
|
92
|
+
delete headers['Content-Type'];
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
// Use JSON for text-only requests
|
|
96
|
+
headers['Content-Type'] = 'application/json';
|
|
97
|
+
body = JSON.stringify(request);
|
|
98
|
+
}
|
|
99
|
+
console.log('Sending request to ReactBridge API:', { url, headers, body, timeoutMs });
|
|
63
100
|
const response = yield fetch(url, {
|
|
64
101
|
method: 'POST',
|
|
65
|
-
headers
|
|
66
|
-
body
|
|
102
|
+
headers,
|
|
103
|
+
body,
|
|
67
104
|
signal,
|
|
68
105
|
});
|
|
106
|
+
console.log('Received response from ReactBridge API:', response);
|
|
69
107
|
// Clear any manual timeout timer if set
|
|
70
108
|
if (timeoutId) {
|
|
71
109
|
clearTimeout(timeoutId);
|
|
@@ -91,6 +129,28 @@ class ReactBridgeAPI {
|
|
|
91
129
|
return this.sendMessage(request);
|
|
92
130
|
});
|
|
93
131
|
}
|
|
132
|
+
// Helper methods for different request types
|
|
133
|
+
sendTextRequest(userId, query, context) {
|
|
134
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
135
|
+
const request = Object.assign({ userId,
|
|
136
|
+
query }, context);
|
|
137
|
+
return this.sendMessage(request);
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
sendImageRequest(userId_1, imageFile_1) {
|
|
141
|
+
return __awaiter(this, arguments, void 0, function* (userId, imageFile, query = '', context) {
|
|
142
|
+
const request = Object.assign({ userId,
|
|
143
|
+
query, image: imageFile, modalityHint: 'image' }, context);
|
|
144
|
+
return this.sendMessage(request);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
sendDocumentRequest(userId_1, documentFile_1) {
|
|
148
|
+
return __awaiter(this, arguments, void 0, function* (userId, documentFile, query = '', context) {
|
|
149
|
+
const request = Object.assign({ userId,
|
|
150
|
+
query, document: documentFile, modalityHint: 'document' }, context);
|
|
151
|
+
return this.sendMessage(request);
|
|
152
|
+
});
|
|
153
|
+
}
|
|
94
154
|
}
|
|
95
155
|
|
|
96
156
|
const lightTheme = {
|
|
@@ -281,16 +341,27 @@ function useReactBridge({ onIntentDetected, currentContext, onError, onSpeechSta
|
|
|
281
341
|
previousContextRef.current = currentContext;
|
|
282
342
|
}
|
|
283
343
|
}, [currentContext]);
|
|
284
|
-
const sendChatQuery = useCallback((
|
|
285
|
-
|
|
344
|
+
const sendChatQuery = useCallback((queryOrOptions) => __awaiter(this, void 0, void 0, function* () {
|
|
345
|
+
const isMultimodal = typeof queryOrOptions === 'object';
|
|
346
|
+
const query = isMultimodal ? (queryOrOptions.query || '') : queryOrOptions;
|
|
347
|
+
const image = isMultimodal ? queryOrOptions.image : undefined;
|
|
348
|
+
const document = isMultimodal ? queryOrOptions.document : undefined;
|
|
349
|
+
if (!query.trim() && !image && !document)
|
|
286
350
|
return;
|
|
287
351
|
setIsLoading(true);
|
|
288
352
|
setError(null);
|
|
289
|
-
// Add user message
|
|
353
|
+
// Add user message with file info if present
|
|
354
|
+
let messageContent = query;
|
|
355
|
+
if (image) {
|
|
356
|
+
messageContent = messageContent ? `${messageContent} [Image: ${image.name}]` : `[Image: ${image.name}]`;
|
|
357
|
+
}
|
|
358
|
+
else if (document) {
|
|
359
|
+
messageContent = messageContent ? `${messageContent} [Document: ${document.name}]` : `[Document: ${document.name}]`;
|
|
360
|
+
}
|
|
290
361
|
const userMessage = {
|
|
291
362
|
id: `user-${Date.now()}`,
|
|
292
363
|
role: 'user',
|
|
293
|
-
content:
|
|
364
|
+
content: messageContent,
|
|
294
365
|
timestamp: new Date(),
|
|
295
366
|
};
|
|
296
367
|
setMessages(prev => [...prev, userMessage]);
|
|
@@ -305,6 +376,10 @@ function useReactBridge({ onIntentDetected, currentContext, onError, onSpeechSta
|
|
|
305
376
|
userRecentActivity: currentContext.userRecentActivity,
|
|
306
377
|
interfaceState: currentContext.interfaceState,
|
|
307
378
|
sessionId: sessionId || undefined,
|
|
379
|
+
// Add multimodal fields
|
|
380
|
+
image,
|
|
381
|
+
document,
|
|
382
|
+
modalityHint: image ? 'image' : document ? 'document' : undefined,
|
|
308
383
|
};
|
|
309
384
|
lastRequestRef.current = request;
|
|
310
385
|
const response = yield api.sendMessage(request);
|
|
@@ -446,6 +521,68 @@ const MESSAGE_ICON_SVG = (React.createElement("svg", { xmlns: "http://www.w3.org
|
|
|
446
521
|
// Microphone Icon SVG
|
|
447
522
|
const MIC_ICON_SVG$1 = (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "1em", height: "1em", fill: "currentColor" },
|
|
448
523
|
React.createElement("path", { d: "M12 14c1.66 0 2.99-1.34 2.99-3L15 5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm5.3-3c0 3-2.54 5.1-5.3 5.1S6.7 14 6.7 11H5c0 3.41 2.72 6.23 6 6.72V21h2v-3.28c3.28-.48 6-3.3 6-6.72h-1.7z" })));
|
|
524
|
+
// Plus Icon SVG
|
|
525
|
+
const PLUS_ICON_SVG$1 = (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "1em", height: "1em", fill: "currentColor" },
|
|
526
|
+
React.createElement("path", { d: "M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" })));
|
|
527
|
+
// Photo Icon SVG
|
|
528
|
+
const PHOTO_ICON_SVG = (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "1em", height: "1em", fill: "currentColor" },
|
|
529
|
+
React.createElement("path", { d: "M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z" })));
|
|
530
|
+
// File Icon SVG
|
|
531
|
+
const FILE_ICON_SVG = (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "1em", height: "1em", fill: "currentColor" },
|
|
532
|
+
React.createElement("path", { d: "M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z" })));
|
|
533
|
+
// Typing Indicator Component
|
|
534
|
+
const TypingIndicator = ({ theme }) => (React.createElement("div", { style: {
|
|
535
|
+
display: "flex",
|
|
536
|
+
justifyContent: "flex-start",
|
|
537
|
+
marginBottom: theme.spacing.md,
|
|
538
|
+
paddingLeft: theme.spacing.md,
|
|
539
|
+
} },
|
|
540
|
+
React.createElement("div", { style: {
|
|
541
|
+
display: "flex",
|
|
542
|
+
alignItems: "center",
|
|
543
|
+
gap: "4px",
|
|
544
|
+
padding: theme.spacing.sm,
|
|
545
|
+
backgroundColor: theme.colors.surface,
|
|
546
|
+
borderRadius: theme.borderRadius,
|
|
547
|
+
boxShadow: theme.boxShadow,
|
|
548
|
+
maxWidth: "70%",
|
|
549
|
+
} },
|
|
550
|
+
React.createElement("div", { style: {
|
|
551
|
+
width: "8px",
|
|
552
|
+
height: "8px",
|
|
553
|
+
borderRadius: "50%",
|
|
554
|
+
backgroundColor: theme.colors.primary,
|
|
555
|
+
animation: "typing-dot 1.4s infinite ease-in-out",
|
|
556
|
+
animationDelay: "0s",
|
|
557
|
+
} }),
|
|
558
|
+
React.createElement("div", { style: {
|
|
559
|
+
width: "8px",
|
|
560
|
+
height: "8px",
|
|
561
|
+
borderRadius: "50%",
|
|
562
|
+
backgroundColor: theme.colors.primary,
|
|
563
|
+
animation: "typing-dot 1.4s infinite ease-in-out",
|
|
564
|
+
animationDelay: "0.2s",
|
|
565
|
+
} }),
|
|
566
|
+
React.createElement("div", { style: {
|
|
567
|
+
width: "8px",
|
|
568
|
+
height: "8px",
|
|
569
|
+
borderRadius: "50%",
|
|
570
|
+
backgroundColor: theme.colors.primary,
|
|
571
|
+
animation: "typing-dot 1.4s infinite ease-in-out",
|
|
572
|
+
animationDelay: "0.4s",
|
|
573
|
+
} }),
|
|
574
|
+
React.createElement("style", null, `
|
|
575
|
+
@keyframes typing-dot {
|
|
576
|
+
0%, 60%, 100% {
|
|
577
|
+
transform: translateY(0);
|
|
578
|
+
opacity: 0.4;
|
|
579
|
+
}
|
|
580
|
+
30% {
|
|
581
|
+
transform: translateY(-10px);
|
|
582
|
+
opacity: 1;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
`))));
|
|
449
586
|
// Default styling constants for the widget wrapper
|
|
450
587
|
const defaultToggleButtonClass = "fixed bottom-6 right-6 z-40 w-14 h-14 rounded-full shadow-lg text-white bg-blue-600 hover:bg-blue-700 transition-all flex justify-center items-center cursor-pointer text-2xl";
|
|
451
588
|
function ReactBridgeChatbox({ onIntentDetected, currentContext, placeholder = "Type your message...", height = "500px", width = "100%", theme: themeOverride, renderMessage, onError,
|
|
@@ -459,7 +596,7 @@ toggleIcon = MESSAGE_ICON_SVG, // <<< NOW USES THE PURE SVG CONSTANT
|
|
|
459
596
|
toggleButtonClass = defaultToggleButtonClass, toggleButtonTitle = "Open chat assistant", }) {
|
|
460
597
|
const { theme: contextTheme } = useReactBridgeContext();
|
|
461
598
|
const theme = Object.assign(Object.assign({}, contextTheme), themeOverride);
|
|
462
|
-
const { messages, isLoading, sendChatQuery, isListening, startVoiceInput, stopVoiceInput } = useReactBridge({
|
|
599
|
+
const { messages, isLoading, sendChatQuery, isListening, startVoiceInput, stopVoiceInput, } = useReactBridge({
|
|
463
600
|
onIntentDetected,
|
|
464
601
|
currentContext,
|
|
465
602
|
onError,
|
|
@@ -471,7 +608,12 @@ toggleButtonClass = defaultToggleButtonClass, toggleButtonTitle = "Open chat ass
|
|
|
471
608
|
const [inputValue, setInputValue] = useState("");
|
|
472
609
|
// New: Manage widget open/closed state
|
|
473
610
|
const [isOpen, setIsOpen] = useState(defaultOpen);
|
|
611
|
+
// Upload functionality state
|
|
612
|
+
const [isUploadMenuOpen, setIsUploadMenuOpen] = useState(false);
|
|
613
|
+
const [selectedFile, setSelectedFile] = useState(null);
|
|
614
|
+
const [filePreview, setFilePreview] = useState(null);
|
|
474
615
|
const messagesEndRef = useRef(null);
|
|
616
|
+
const containerRef = useRef(null);
|
|
475
617
|
// Fallback styles for header
|
|
476
618
|
const finalHeaderBgColor = headerBgColor || theme.colors.primary;
|
|
477
619
|
const finalTitleTextColor = titleTextColor || "#ffffff"; // Default to white for contrast
|
|
@@ -480,14 +622,92 @@ toggleButtonClass = defaultToggleButtonClass, toggleButtonTitle = "Open chat ass
|
|
|
480
622
|
var _a;
|
|
481
623
|
(_a = messagesEndRef.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ behavior: "smooth" });
|
|
482
624
|
}, [messages]);
|
|
625
|
+
// Close upload menu and widget when clicking outside
|
|
626
|
+
useEffect(() => {
|
|
627
|
+
const handleClickOutside = (event) => {
|
|
628
|
+
if (containerRef.current &&
|
|
629
|
+
!containerRef.current.contains(event.target)) {
|
|
630
|
+
setIsUploadMenuOpen(false);
|
|
631
|
+
if (isOpen) {
|
|
632
|
+
setIsOpen(false);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
};
|
|
636
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
637
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
638
|
+
}, [isUploadMenuOpen, isOpen]);
|
|
483
639
|
const handleSubmit = (e) => __awaiter(this, void 0, void 0, function* () {
|
|
484
640
|
e.preventDefault();
|
|
485
|
-
if (!inputValue.trim() || isLoading)
|
|
641
|
+
if ((!inputValue.trim() && !selectedFile) || isLoading)
|
|
486
642
|
return;
|
|
643
|
+
const query = inputValue.trim();
|
|
487
644
|
setInputValue("");
|
|
488
|
-
//
|
|
489
|
-
|
|
645
|
+
// Handle multimodal request
|
|
646
|
+
if (selectedFile && filePreview) {
|
|
647
|
+
if (filePreview.type === "image") {
|
|
648
|
+
yield sendChatQuery({ image: selectedFile, query });
|
|
649
|
+
}
|
|
650
|
+
else if (filePreview.type === "document") {
|
|
651
|
+
yield sendChatQuery({ document: selectedFile, query });
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
else {
|
|
655
|
+
yield sendChatQuery(query);
|
|
656
|
+
}
|
|
657
|
+
// Clear file selection after sending
|
|
658
|
+
setSelectedFile(null);
|
|
659
|
+
setFilePreview(null);
|
|
490
660
|
});
|
|
661
|
+
// File validation and handling
|
|
662
|
+
const validateAndSetFile = (file, type) => {
|
|
663
|
+
const imageTypes = ["image/png", "image/jpeg", "image/jpg", "image/webp"];
|
|
664
|
+
const documentTypes = [
|
|
665
|
+
"application/pdf",
|
|
666
|
+
"application/msword",
|
|
667
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
668
|
+
"text/plain",
|
|
669
|
+
];
|
|
670
|
+
const allowedTypes = type === "image" ? imageTypes : documentTypes;
|
|
671
|
+
if (!allowedTypes.includes(file.type)) {
|
|
672
|
+
if (onError) {
|
|
673
|
+
onError(new Error(`Invalid file type. Please select a valid ${type} file.`));
|
|
674
|
+
}
|
|
675
|
+
return false;
|
|
676
|
+
}
|
|
677
|
+
setSelectedFile(file);
|
|
678
|
+
if (type === "image") {
|
|
679
|
+
const url = URL.createObjectURL(file);
|
|
680
|
+
setFilePreview({ type: "image", url, name: file.name });
|
|
681
|
+
}
|
|
682
|
+
else {
|
|
683
|
+
setFilePreview({ type: "document", name: file.name });
|
|
684
|
+
}
|
|
685
|
+
setIsUploadMenuOpen(false);
|
|
686
|
+
return true;
|
|
687
|
+
};
|
|
688
|
+
const handleFileSelect = (type) => {
|
|
689
|
+
const input = document.createElement("input");
|
|
690
|
+
input.type = "file";
|
|
691
|
+
input.accept =
|
|
692
|
+
type === "image"
|
|
693
|
+
? "image/png,image/jpeg,image/jpg,image/webp"
|
|
694
|
+
: "application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,text/plain";
|
|
695
|
+
input.onchange = (e) => {
|
|
696
|
+
var _a;
|
|
697
|
+
const file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
|
|
698
|
+
if (file) {
|
|
699
|
+
validateAndSetFile(file, type);
|
|
700
|
+
}
|
|
701
|
+
};
|
|
702
|
+
input.click();
|
|
703
|
+
};
|
|
704
|
+
const removeFile = () => {
|
|
705
|
+
if (filePreview === null || filePreview === void 0 ? void 0 : filePreview.url) {
|
|
706
|
+
URL.revokeObjectURL(filePreview.url);
|
|
707
|
+
}
|
|
708
|
+
setSelectedFile(null);
|
|
709
|
+
setFilePreview(null);
|
|
710
|
+
};
|
|
491
711
|
const defaultRenderMessage = (message) => {
|
|
492
712
|
const isUser = message.role === "user";
|
|
493
713
|
const isSystem = message.role === "system";
|
|
@@ -514,7 +734,7 @@ toggleButtonClass = defaultToggleButtonClass, toggleButtonTitle = "Open chat ass
|
|
|
514
734
|
// --- RENDER LOGIC FOR 'BASIC' MODE (Original Behavior) ---
|
|
515
735
|
if (renderMode === "basic") {
|
|
516
736
|
// Renders the chat component only, using the height/width props directly
|
|
517
|
-
return (React.createElement("div", { style: {
|
|
737
|
+
return (React.createElement("div", { ref: containerRef, style: {
|
|
518
738
|
width,
|
|
519
739
|
height,
|
|
520
740
|
display: "flex",
|
|
@@ -530,14 +750,21 @@ toggleButtonClass = defaultToggleButtonClass, toggleButtonTitle = "Open chat ass
|
|
|
530
750
|
overflowY: "auto",
|
|
531
751
|
padding: theme.spacing.md,
|
|
532
752
|
} },
|
|
533
|
-
messages.map((message) => renderMessage
|
|
753
|
+
messages.map((message) => renderMessage
|
|
754
|
+
? renderMessage(message)
|
|
755
|
+
: defaultRenderMessage(message)),
|
|
756
|
+
isLoading && React.createElement(TypingIndicator, { theme: theme }),
|
|
534
757
|
React.createElement("div", { ref: messagesEndRef })),
|
|
535
758
|
React.createElement("form", { onSubmit: handleSubmit, style: {
|
|
536
759
|
padding: theme.spacing.md,
|
|
537
760
|
borderTop: `1px solid ${theme.colors.border}`,
|
|
538
761
|
backgroundColor: theme.colors.surface,
|
|
539
762
|
} },
|
|
540
|
-
React.createElement("div", { style: {
|
|
763
|
+
React.createElement("div", { style: {
|
|
764
|
+
display: "flex",
|
|
765
|
+
gap: theme.spacing.sm,
|
|
766
|
+
alignItems: "center",
|
|
767
|
+
} },
|
|
541
768
|
React.createElement("input", { type: "text", value: inputValue, onChange: (e) => setInputValue(e.target.value), placeholder: placeholder, disabled: isLoading, style: {
|
|
542
769
|
flex: 1,
|
|
543
770
|
padding: theme.spacing.sm,
|
|
@@ -548,9 +775,65 @@ toggleButtonClass = defaultToggleButtonClass, toggleButtonTitle = "Open chat ass
|
|
|
548
775
|
color: theme.colors.text,
|
|
549
776
|
outline: "none",
|
|
550
777
|
} }),
|
|
778
|
+
React.createElement("button", { type: "button", onClick: () => setIsUploadMenuOpen(!isUploadMenuOpen), disabled: isLoading, title: "Attach file", style: {
|
|
779
|
+
padding: theme.spacing.sm,
|
|
780
|
+
backgroundColor: theme.colors.secondary,
|
|
781
|
+
color: "#ffffff",
|
|
782
|
+
border: "none",
|
|
783
|
+
borderRadius: theme.borderRadius,
|
|
784
|
+
cursor: isLoading ? "not-allowed" : "pointer",
|
|
785
|
+
opacity: isLoading ? 0.5 : 1,
|
|
786
|
+
display: "flex",
|
|
787
|
+
alignItems: "center",
|
|
788
|
+
justifyContent: "center",
|
|
789
|
+
width: "40px",
|
|
790
|
+
height: "40px",
|
|
791
|
+
} }, PLUS_ICON_SVG$1),
|
|
792
|
+
isUploadMenuOpen && (React.createElement("div", { style: {
|
|
793
|
+
position: "absolute",
|
|
794
|
+
bottom: "60px",
|
|
795
|
+
right: "10px",
|
|
796
|
+
backgroundColor: theme.colors.background,
|
|
797
|
+
border: `1px solid ${theme.colors.border}`,
|
|
798
|
+
borderRadius: theme.borderRadius,
|
|
799
|
+
boxShadow: theme.boxShadow,
|
|
800
|
+
zIndex: 1000,
|
|
801
|
+
minWidth: "150px",
|
|
802
|
+
} },
|
|
803
|
+
React.createElement("button", { onClick: () => handleFileSelect("image"), style: {
|
|
804
|
+
width: "100%",
|
|
805
|
+
padding: theme.spacing.md,
|
|
806
|
+
border: "none",
|
|
807
|
+
backgroundColor: "transparent",
|
|
808
|
+
color: theme.colors.text,
|
|
809
|
+
cursor: "pointer",
|
|
810
|
+
display: "flex",
|
|
811
|
+
alignItems: "center",
|
|
812
|
+
gap: theme.spacing.sm,
|
|
813
|
+
borderRadius: `${theme.borderRadius} ${theme.borderRadius} 0 0`,
|
|
814
|
+
} },
|
|
815
|
+
PHOTO_ICON_SVG,
|
|
816
|
+
"Upload Image"),
|
|
817
|
+
React.createElement("button", { onClick: () => handleFileSelect("document"), style: {
|
|
818
|
+
width: "100%",
|
|
819
|
+
padding: theme.spacing.md,
|
|
820
|
+
border: "none",
|
|
821
|
+
backgroundColor: "transparent",
|
|
822
|
+
color: theme.colors.text,
|
|
823
|
+
cursor: "pointer",
|
|
824
|
+
display: "flex",
|
|
825
|
+
alignItems: "center",
|
|
826
|
+
gap: theme.spacing.sm,
|
|
827
|
+
borderRadius: `0 0 ${theme.borderRadius} ${theme.borderRadius}`,
|
|
828
|
+
borderTop: `1px solid ${theme.colors.border}`,
|
|
829
|
+
} },
|
|
830
|
+
FILE_ICON_SVG,
|
|
831
|
+
"Upload Document"))),
|
|
551
832
|
React.createElement("button", { type: "button", onClick: isListening ? stopVoiceInput : startVoiceInput, disabled: isLoading, title: isListening ? "Stop recording" : "Start voice input", style: {
|
|
552
833
|
padding: theme.spacing.sm,
|
|
553
|
-
backgroundColor: isListening
|
|
834
|
+
backgroundColor: isListening
|
|
835
|
+
? theme.colors.error
|
|
836
|
+
: theme.colors.secondary,
|
|
554
837
|
color: "#ffffff",
|
|
555
838
|
border: "none",
|
|
556
839
|
borderRadius: theme.borderRadius,
|
|
@@ -562,16 +845,55 @@ toggleButtonClass = defaultToggleButtonClass, toggleButtonTitle = "Open chat ass
|
|
|
562
845
|
width: "40px",
|
|
563
846
|
height: "40px",
|
|
564
847
|
} }, MIC_ICON_SVG$1),
|
|
565
|
-
React.createElement("button", { type: "submit", disabled: isLoading || !inputValue.trim(), style: {
|
|
848
|
+
React.createElement("button", { type: "submit", disabled: isLoading || (!inputValue.trim() && !selectedFile), style: {
|
|
566
849
|
padding: `${theme.spacing.sm} ${theme.spacing.md}`,
|
|
567
850
|
fontSize: theme.fontSizes.md,
|
|
568
851
|
backgroundColor: theme.colors.primary,
|
|
569
852
|
color: "#ffffff",
|
|
570
853
|
border: "none",
|
|
571
854
|
borderRadius: theme.borderRadius,
|
|
572
|
-
cursor: isLoading || !inputValue.trim()
|
|
573
|
-
|
|
574
|
-
|
|
855
|
+
cursor: isLoading || (!inputValue.trim() && !selectedFile)
|
|
856
|
+
? "not-allowed"
|
|
857
|
+
: "pointer",
|
|
858
|
+
opacity: isLoading || (!inputValue.trim() && !selectedFile) ? 0.5 : 1,
|
|
859
|
+
} }, isLoading ? "Sending..." : "Send")),
|
|
860
|
+
filePreview && (React.createElement("div", { style: {
|
|
861
|
+
marginTop: theme.spacing.sm,
|
|
862
|
+
padding: theme.spacing.sm,
|
|
863
|
+
backgroundColor: theme.colors.surface,
|
|
864
|
+
border: `1px solid ${theme.colors.border}`,
|
|
865
|
+
borderRadius: theme.borderRadius,
|
|
866
|
+
display: "flex",
|
|
867
|
+
alignItems: "center",
|
|
868
|
+
gap: theme.spacing.sm,
|
|
869
|
+
} },
|
|
870
|
+
filePreview.type === "image" && filePreview.url ? (React.createElement("img", { src: filePreview.url, alt: "Preview", style: {
|
|
871
|
+
width: "40px",
|
|
872
|
+
height: "40px",
|
|
873
|
+
objectFit: "cover",
|
|
874
|
+
borderRadius: theme.borderRadius,
|
|
875
|
+
} })) : (React.createElement("div", { style: {
|
|
876
|
+
width: "40px",
|
|
877
|
+
height: "40px",
|
|
878
|
+
backgroundColor: theme.colors.secondary,
|
|
879
|
+
borderRadius: theme.borderRadius,
|
|
880
|
+
display: "flex",
|
|
881
|
+
alignItems: "center",
|
|
882
|
+
justifyContent: "center",
|
|
883
|
+
} }, FILE_ICON_SVG)),
|
|
884
|
+
React.createElement("div", { style: {
|
|
885
|
+
flex: 1,
|
|
886
|
+
fontSize: theme.fontSizes.sm,
|
|
887
|
+
color: theme.colors.text,
|
|
888
|
+
} }, filePreview.name),
|
|
889
|
+
React.createElement("button", { type: "button", onClick: removeFile, style: {
|
|
890
|
+
padding: "4px",
|
|
891
|
+
backgroundColor: "transparent",
|
|
892
|
+
border: "none",
|
|
893
|
+
color: theme.colors.error,
|
|
894
|
+
cursor: "pointer",
|
|
895
|
+
fontSize: "18px",
|
|
896
|
+
}, title: "Remove file" }, "\u00D7"))))));
|
|
575
897
|
}
|
|
576
898
|
// --- RENDER LOGIC FOR 'STANDARD' MODE (Widget Behavior) ---
|
|
577
899
|
// Determine fixed positioning class for the widget
|
|
@@ -587,11 +909,14 @@ toggleButtonClass = defaultToggleButtonClass, toggleButtonTitle = "Open chat ass
|
|
|
587
909
|
return (React.createElement("button", { className: toggleButtonClass, onClick: () => setIsOpen(true), title: toggleButtonTitle, style: Object.assign(Object.assign(Object.assign({
|
|
588
910
|
// Apply widget-specific fixed positioning
|
|
589
911
|
position: "fixed", zIndex: 40 }, togglePositionClass), { backgroundColor: finalHeaderBgColor }), (toggleButtonClass === defaultToggleButtonClass && {
|
|
590
|
-
width:
|
|
912
|
+
width: "56px",
|
|
913
|
+
height: "56px",
|
|
914
|
+
borderRadius: "50%",
|
|
915
|
+
boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)",
|
|
591
916
|
})) }, toggleIcon));
|
|
592
917
|
}
|
|
593
918
|
// Render the full widget when open
|
|
594
|
-
return (React.createElement("div", { style: Object.assign({ width: width, height: height, display: "flex", flexDirection: "column", boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)", borderRadius: theme.borderRadius, overflow: "hidden", fontFamily: "system-ui, -apple-system, sans-serif", position: "fixed", zIndex: 50 }, widgetPositionClass) },
|
|
919
|
+
return (React.createElement("div", { ref: containerRef, style: Object.assign({ width: width, height: height, display: "flex", flexDirection: "column", boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)", borderRadius: theme.borderRadius, overflow: "hidden", fontFamily: "system-ui, -apple-system, sans-serif", position: "fixed", zIndex: 50 }, widgetPositionClass) },
|
|
595
920
|
React.createElement("div", { style: {
|
|
596
921
|
padding: "10px 15px",
|
|
597
922
|
backgroundColor: finalHeaderBgColor,
|
|
@@ -606,7 +931,11 @@ toggleButtonClass = defaultToggleButtonClass, toggleButtonTitle = "Open chat ass
|
|
|
606
931
|
fontWeight: "bold",
|
|
607
932
|
fontSize: theme.fontSizes.md,
|
|
608
933
|
} },
|
|
609
|
-
titleIcon && (React.createElement("span", { style: {
|
|
934
|
+
titleIcon && (React.createElement("span", { style: {
|
|
935
|
+
marginRight: theme.spacing.sm,
|
|
936
|
+
display: "flex",
|
|
937
|
+
alignItems: "center",
|
|
938
|
+
} }, titleIcon)),
|
|
610
939
|
titleText),
|
|
611
940
|
React.createElement("button", { onClick: () => setIsOpen(false), style: {
|
|
612
941
|
background: "none",
|
|
@@ -624,13 +953,18 @@ toggleButtonClass = defaultToggleButtonClass, toggleButtonTitle = "Open chat ass
|
|
|
624
953
|
backgroundColor: theme.colors.background,
|
|
625
954
|
} },
|
|
626
955
|
messages.map((message) => renderMessage ? renderMessage(message) : defaultRenderMessage(message)),
|
|
956
|
+
isLoading && React.createElement(TypingIndicator, { theme: theme }),
|
|
627
957
|
React.createElement("div", { ref: messagesEndRef })),
|
|
628
958
|
React.createElement("form", { onSubmit: handleSubmit, style: {
|
|
629
959
|
padding: theme.spacing.md,
|
|
630
960
|
borderTop: `1px solid ${theme.colors.border}`,
|
|
631
961
|
backgroundColor: theme.colors.surface,
|
|
632
962
|
} },
|
|
633
|
-
React.createElement("div", { style: {
|
|
963
|
+
React.createElement("div", { style: {
|
|
964
|
+
display: "flex",
|
|
965
|
+
gap: theme.spacing.sm,
|
|
966
|
+
alignItems: "center",
|
|
967
|
+
} },
|
|
634
968
|
React.createElement("input", { type: "text", value: inputValue, onChange: (e) => setInputValue(e.target.value), placeholder: placeholder, disabled: isLoading, style: {
|
|
635
969
|
flex: 1,
|
|
636
970
|
padding: theme.spacing.sm,
|
|
@@ -641,9 +975,67 @@ toggleButtonClass = defaultToggleButtonClass, toggleButtonTitle = "Open chat ass
|
|
|
641
975
|
color: theme.colors.text,
|
|
642
976
|
outline: "none",
|
|
643
977
|
} }),
|
|
978
|
+
React.createElement("button", { type: "button", onClick: () => setIsUploadMenuOpen(!isUploadMenuOpen), disabled: isLoading, title: "Attach file", style: {
|
|
979
|
+
padding: theme.spacing.sm,
|
|
980
|
+
color: theme.colors.border,
|
|
981
|
+
border: "none",
|
|
982
|
+
borderRadius: theme.borderRadius,
|
|
983
|
+
cursor: isLoading ? "not-allowed" : "pointer",
|
|
984
|
+
opacity: isLoading ? 0.5 : 1,
|
|
985
|
+
display: "flex",
|
|
986
|
+
alignItems: "center",
|
|
987
|
+
justifyContent: "center",
|
|
988
|
+
width: "40px",
|
|
989
|
+
height: "40px",
|
|
990
|
+
} }, PLUS_ICON_SVG$1),
|
|
991
|
+
isUploadMenuOpen && (React.createElement("div", { style: {
|
|
992
|
+
position: "absolute",
|
|
993
|
+
bottom: "60px",
|
|
994
|
+
right: "10px",
|
|
995
|
+
backgroundColor: theme.colors.background,
|
|
996
|
+
border: `1px solid ${theme.colors.border}`,
|
|
997
|
+
borderRadius: theme.borderRadius,
|
|
998
|
+
boxShadow: theme.boxShadow,
|
|
999
|
+
zIndex: 1000,
|
|
1000
|
+
minWidth: "150px",
|
|
1001
|
+
} },
|
|
1002
|
+
React.createElement("button", { onClick: (e) => {
|
|
1003
|
+
e.preventDefault();
|
|
1004
|
+
handleFileSelect("image");
|
|
1005
|
+
}, style: {
|
|
1006
|
+
width: "100%",
|
|
1007
|
+
padding: theme.spacing.md,
|
|
1008
|
+
border: "none",
|
|
1009
|
+
backgroundColor: "transparent",
|
|
1010
|
+
color: theme.colors.text,
|
|
1011
|
+
cursor: "pointer",
|
|
1012
|
+
display: "flex",
|
|
1013
|
+
alignItems: "center",
|
|
1014
|
+
gap: theme.spacing.sm,
|
|
1015
|
+
borderRadius: `${theme.borderRadius} ${theme.borderRadius} 0 0`,
|
|
1016
|
+
} },
|
|
1017
|
+
PHOTO_ICON_SVG,
|
|
1018
|
+
"Upload Image"),
|
|
1019
|
+
React.createElement("button", { onClick: (e) => {
|
|
1020
|
+
e.preventDefault();
|
|
1021
|
+
handleFileSelect("document");
|
|
1022
|
+
}, style: {
|
|
1023
|
+
width: "100%",
|
|
1024
|
+
padding: theme.spacing.md,
|
|
1025
|
+
border: "none",
|
|
1026
|
+
backgroundColor: "transparent",
|
|
1027
|
+
color: theme.colors.text,
|
|
1028
|
+
cursor: "pointer",
|
|
1029
|
+
display: "flex",
|
|
1030
|
+
alignItems: "center",
|
|
1031
|
+
gap: theme.spacing.sm,
|
|
1032
|
+
borderRadius: `0 0 ${theme.borderRadius} ${theme.borderRadius}`,
|
|
1033
|
+
borderTop: `1px solid ${theme.colors.border}`,
|
|
1034
|
+
} },
|
|
1035
|
+
FILE_ICON_SVG,
|
|
1036
|
+
"Upload Document"))),
|
|
644
1037
|
React.createElement("button", { type: "button", onClick: isListening ? stopVoiceInput : startVoiceInput, disabled: isLoading, title: isListening ? "Stop recording" : "Start voice input", style: {
|
|
645
1038
|
padding: theme.spacing.sm,
|
|
646
|
-
// backgroundColor: isListening ? theme.colors.error : theme.colors.primary,
|
|
647
1039
|
color: isListening ? theme.colors.primary : theme.colors.border,
|
|
648
1040
|
border: "none",
|
|
649
1041
|
borderRadius: theme.borderRadius,
|
|
@@ -655,21 +1047,63 @@ toggleButtonClass = defaultToggleButtonClass, toggleButtonTitle = "Open chat ass
|
|
|
655
1047
|
width: "40px",
|
|
656
1048
|
height: "40px",
|
|
657
1049
|
} }, MIC_ICON_SVG$1),
|
|
658
|
-
React.createElement("button", { type: "submit", disabled: isLoading || !inputValue.trim(), style: {
|
|
1050
|
+
React.createElement("button", { type: "submit", disabled: isLoading || (!inputValue.trim() && !selectedFile), style: {
|
|
659
1051
|
padding: `${theme.spacing.sm} ${theme.spacing.md}`,
|
|
660
1052
|
fontSize: theme.fontSizes.md,
|
|
661
1053
|
backgroundColor: theme.colors.primary,
|
|
662
1054
|
color: theme.colors.background,
|
|
663
1055
|
border: "none",
|
|
664
1056
|
borderRadius: theme.borderRadius,
|
|
665
|
-
cursor: isLoading || !inputValue.trim()
|
|
666
|
-
|
|
667
|
-
|
|
1057
|
+
cursor: isLoading || (!inputValue.trim() && !selectedFile)
|
|
1058
|
+
? "not-allowed"
|
|
1059
|
+
: "pointer",
|
|
1060
|
+
opacity: isLoading || (!inputValue.trim() && !selectedFile) ? 0.5 : 1,
|
|
1061
|
+
} }, isLoading ? "Sending..." : "Send")),
|
|
1062
|
+
filePreview && (React.createElement("div", { style: {
|
|
1063
|
+
marginTop: theme.spacing.sm,
|
|
1064
|
+
padding: theme.spacing.sm,
|
|
1065
|
+
backgroundColor: theme.colors.surface,
|
|
1066
|
+
border: `1px solid ${theme.colors.border}`,
|
|
1067
|
+
borderRadius: theme.borderRadius,
|
|
1068
|
+
display: "flex",
|
|
1069
|
+
alignItems: "center",
|
|
1070
|
+
gap: theme.spacing.sm,
|
|
1071
|
+
} },
|
|
1072
|
+
filePreview.type === "image" && filePreview.url ? (React.createElement("img", { src: filePreview.url, alt: "Preview", style: {
|
|
1073
|
+
width: "40px",
|
|
1074
|
+
height: "40px",
|
|
1075
|
+
objectFit: "cover",
|
|
1076
|
+
borderRadius: theme.borderRadius,
|
|
1077
|
+
} })) : (React.createElement("div", { style: {
|
|
1078
|
+
width: "40px",
|
|
1079
|
+
height: "40px",
|
|
1080
|
+
backgroundColor: theme.colors.secondary,
|
|
1081
|
+
borderRadius: theme.borderRadius,
|
|
1082
|
+
display: "flex",
|
|
1083
|
+
alignItems: "center",
|
|
1084
|
+
justifyContent: "center",
|
|
1085
|
+
} }, FILE_ICON_SVG)),
|
|
1086
|
+
React.createElement("div", { style: {
|
|
1087
|
+
flex: 1,
|
|
1088
|
+
fontSize: theme.fontSizes.sm,
|
|
1089
|
+
color: theme.colors.text,
|
|
1090
|
+
} }, filePreview.name),
|
|
1091
|
+
React.createElement("button", { type: "button", onClick: removeFile, style: {
|
|
1092
|
+
padding: "4px",
|
|
1093
|
+
backgroundColor: "transparent",
|
|
1094
|
+
border: "none",
|
|
1095
|
+
color: theme.colors.error,
|
|
1096
|
+
cursor: "pointer",
|
|
1097
|
+
fontSize: "18px",
|
|
1098
|
+
}, title: "Remove file" }, "\u00D7"))))));
|
|
668
1099
|
}
|
|
669
1100
|
|
|
670
1101
|
// Microphone Icon SVG
|
|
671
1102
|
const MIC_ICON_SVG = (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "1em", height: "1em", fill: "currentColor" },
|
|
672
1103
|
React.createElement("path", { d: "M12 14c1.66 0 2.99-1.34 2.99-3L15 5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm5.3-3c0 3-2.54 5.1-5.3 5.1S6.7 14 6.7 11H5c0 3.41 2.72 6.23 6 6.72V21h2v-3.28c3.28-.48 6-3.3 6-6.72h-1.7z" })));
|
|
1104
|
+
// Plus Icon SVG
|
|
1105
|
+
const PLUS_ICON_SVG = (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "1em", height: "1em", fill: "currentColor" },
|
|
1106
|
+
React.createElement("path", { d: "M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" })));
|
|
673
1107
|
function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = 'Search...', width = '100%', maxResults = 5, theme: themeOverride, onError, onSpeechStart, onSpeechEnd, onTranscript, onAgentResponse, }) {
|
|
674
1108
|
const { theme: contextTheme } = useReactBridgeContext();
|
|
675
1109
|
const theme = Object.assign(Object.assign({}, contextTheme), themeOverride);
|
|
@@ -684,12 +1118,17 @@ function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = 'Se
|
|
|
684
1118
|
});
|
|
685
1119
|
const [inputValue, setInputValue] = useState('');
|
|
686
1120
|
const [isOpen, setIsOpen] = useState(false);
|
|
1121
|
+
const [isUploadMenuOpen, setIsUploadMenuOpen] = useState(false);
|
|
1122
|
+
const [selectedFile, setSelectedFile] = useState(null);
|
|
1123
|
+
const [filePreview, setFilePreview] = useState(null);
|
|
687
1124
|
const containerRef = useRef(null);
|
|
688
|
-
|
|
1125
|
+
const fileInputRef = useRef(null);
|
|
1126
|
+
// Close dropdown and upload menu when clicking outside
|
|
689
1127
|
useEffect(() => {
|
|
690
1128
|
const handleClickOutside = (event) => {
|
|
691
1129
|
if (containerRef.current && !containerRef.current.contains(event.target)) {
|
|
692
1130
|
setIsOpen(false);
|
|
1131
|
+
setIsUploadMenuOpen(false);
|
|
693
1132
|
}
|
|
694
1133
|
};
|
|
695
1134
|
document.addEventListener('mousedown', handleClickOutside);
|
|
@@ -701,12 +1140,78 @@ function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = 'Se
|
|
|
701
1140
|
setIsOpen(true);
|
|
702
1141
|
}
|
|
703
1142
|
}, [messages]);
|
|
1143
|
+
const handleFileSelect = (type) => {
|
|
1144
|
+
if (fileInputRef.current) {
|
|
1145
|
+
fileInputRef.current.accept = type === 'image'
|
|
1146
|
+
? 'image/png,image/jpeg,image/jpg,image/webp'
|
|
1147
|
+
: 'application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,text/plain';
|
|
1148
|
+
fileInputRef.current.click();
|
|
1149
|
+
}
|
|
1150
|
+
setIsUploadMenuOpen(false);
|
|
1151
|
+
};
|
|
1152
|
+
const handleFileChange = (event) => {
|
|
1153
|
+
var _a;
|
|
1154
|
+
const file = (_a = event.target.files) === null || _a === void 0 ? void 0 : _a[0];
|
|
1155
|
+
if (!file)
|
|
1156
|
+
return;
|
|
1157
|
+
// Validate file type
|
|
1158
|
+
const imageTypes = ['image/png', 'image/jpeg', 'image/jpg', 'image/webp'];
|
|
1159
|
+
const documentTypes = ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'text/plain'];
|
|
1160
|
+
const allowedTypes = file.type.startsWith('image/') ? imageTypes : documentTypes;
|
|
1161
|
+
if (!allowedTypes.includes(file.type)) {
|
|
1162
|
+
if (onError) {
|
|
1163
|
+
onError(new Error(`Invalid file type. Please select a valid ${file.type.startsWith('image/') ? 'image' : 'document'} file.`));
|
|
1164
|
+
}
|
|
1165
|
+
return;
|
|
1166
|
+
}
|
|
1167
|
+
// Validate file size (10MB limit)
|
|
1168
|
+
const maxSize = 10 * 1024 * 1024; // 10MB
|
|
1169
|
+
if (file.size > maxSize) {
|
|
1170
|
+
if (onError) {
|
|
1171
|
+
onError(new Error('File size too large. Please select a file smaller than 10MB.'));
|
|
1172
|
+
}
|
|
1173
|
+
return;
|
|
1174
|
+
}
|
|
1175
|
+
setSelectedFile(file);
|
|
1176
|
+
// Create preview for images
|
|
1177
|
+
if (file.type.startsWith('image/')) {
|
|
1178
|
+
const reader = new FileReader();
|
|
1179
|
+
reader.onload = (e) => {
|
|
1180
|
+
var _a;
|
|
1181
|
+
setFilePreview((_a = e.target) === null || _a === void 0 ? void 0 : _a.result);
|
|
1182
|
+
};
|
|
1183
|
+
reader.readAsDataURL(file);
|
|
1184
|
+
}
|
|
1185
|
+
else {
|
|
1186
|
+
// For documents, show file name
|
|
1187
|
+
setFilePreview(file.name);
|
|
1188
|
+
}
|
|
1189
|
+
};
|
|
1190
|
+
const removeFile = () => {
|
|
1191
|
+
setSelectedFile(null);
|
|
1192
|
+
setFilePreview(null);
|
|
1193
|
+
if (fileInputRef.current) {
|
|
1194
|
+
fileInputRef.current.value = '';
|
|
1195
|
+
}
|
|
1196
|
+
};
|
|
704
1197
|
const handleSubmit = (e) => __awaiter(this, void 0, void 0, function* () {
|
|
705
1198
|
e.preventDefault();
|
|
706
|
-
if (!inputValue.trim() || isLoading)
|
|
1199
|
+
if ((!inputValue.trim() && !selectedFile) || isLoading)
|
|
707
1200
|
return;
|
|
708
|
-
|
|
1201
|
+
const query = inputValue.trim();
|
|
709
1202
|
setInputValue('');
|
|
1203
|
+
// Handle multimodal request
|
|
1204
|
+
if (selectedFile && filePreview) {
|
|
1205
|
+
yield sendChatQuery({
|
|
1206
|
+
query,
|
|
1207
|
+
image: selectedFile.type.startsWith('image/') ? selectedFile : undefined,
|
|
1208
|
+
document: selectedFile.type.startsWith('image/') ? undefined : selectedFile,
|
|
1209
|
+
});
|
|
1210
|
+
removeFile();
|
|
1211
|
+
}
|
|
1212
|
+
else {
|
|
1213
|
+
yield sendChatQuery(query);
|
|
1214
|
+
}
|
|
710
1215
|
});
|
|
711
1216
|
// Get only assistant messages (not system messages)
|
|
712
1217
|
const displayMessages = messages
|
|
@@ -719,10 +1224,11 @@ function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = 'Se
|
|
|
719
1224
|
} },
|
|
720
1225
|
React.createElement("form", { onSubmit: handleSubmit },
|
|
721
1226
|
React.createElement("div", { style: { position: 'relative' } },
|
|
722
|
-
React.createElement("input", {
|
|
1227
|
+
React.createElement("input", { ref: fileInputRef, type: "file", onChange: handleFileChange, style: { display: 'none' } }),
|
|
1228
|
+
React.createElement("input", { type: "text", value: inputValue, onChange: (e) => setInputValue(e.target.value), onFocus: () => displayMessages.length > 0 && setIsOpen(true), placeholder: selectedFile ? `Search with ${selectedFile.name}...` : placeholder, disabled: isLoading, style: {
|
|
723
1229
|
width: '100%',
|
|
724
1230
|
padding: theme.spacing.md,
|
|
725
|
-
paddingRight: '
|
|
1231
|
+
paddingRight: '180px', // Increased to make room for plus, mic, and search buttons
|
|
726
1232
|
fontSize: theme.fontSizes.md,
|
|
727
1233
|
border: `1px solid ${theme.colors.border}`,
|
|
728
1234
|
borderRadius: theme.borderRadius,
|
|
@@ -731,6 +1237,56 @@ function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = 'Se
|
|
|
731
1237
|
outline: 'none',
|
|
732
1238
|
boxSizing: 'border-box',
|
|
733
1239
|
} }),
|
|
1240
|
+
React.createElement("button", { type: "button", onClick: () => setIsUploadMenuOpen(!isUploadMenuOpen), disabled: isLoading, title: "Upload file", style: {
|
|
1241
|
+
position: 'absolute',
|
|
1242
|
+
right: '105px', // Position before the mic button
|
|
1243
|
+
top: '50%',
|
|
1244
|
+
transform: 'translateY(-50%)',
|
|
1245
|
+
padding: theme.spacing.sm,
|
|
1246
|
+
marginRight: theme.spacing.xs,
|
|
1247
|
+
color: theme.colors.border,
|
|
1248
|
+
border: "none",
|
|
1249
|
+
borderRadius: theme.borderRadius,
|
|
1250
|
+
cursor: isLoading ? "not-allowed" : "pointer",
|
|
1251
|
+
opacity: isLoading ? 0.5 : 1,
|
|
1252
|
+
display: "flex",
|
|
1253
|
+
alignItems: "center",
|
|
1254
|
+
justifyContent: "center",
|
|
1255
|
+
width: "32px",
|
|
1256
|
+
height: "32px",
|
|
1257
|
+
} }, PLUS_ICON_SVG),
|
|
1258
|
+
isUploadMenuOpen && (React.createElement("div", { style: {
|
|
1259
|
+
position: 'absolute',
|
|
1260
|
+
right: '105px',
|
|
1261
|
+
top: '100%',
|
|
1262
|
+
marginTop: theme.spacing.xs,
|
|
1263
|
+
backgroundColor: theme.colors.background,
|
|
1264
|
+
border: `1px solid ${theme.colors.border}`,
|
|
1265
|
+
borderRadius: theme.borderRadius,
|
|
1266
|
+
boxShadow: theme.boxShadow,
|
|
1267
|
+
zIndex: 1000,
|
|
1268
|
+
minWidth: '120px',
|
|
1269
|
+
} },
|
|
1270
|
+
React.createElement("button", { type: "button", onClick: () => handleFileSelect('image'), style: {
|
|
1271
|
+
width: '100%',
|
|
1272
|
+
padding: theme.spacing.sm,
|
|
1273
|
+
backgroundColor: 'transparent',
|
|
1274
|
+
border: 'none',
|
|
1275
|
+
color: theme.colors.text,
|
|
1276
|
+
cursor: 'pointer',
|
|
1277
|
+
textAlign: 'left',
|
|
1278
|
+
fontSize: theme.fontSizes.sm,
|
|
1279
|
+
} }, "\uD83D\uDCF7 Image"),
|
|
1280
|
+
React.createElement("button", { type: "button", onClick: () => handleFileSelect('document'), style: {
|
|
1281
|
+
width: '100%',
|
|
1282
|
+
padding: theme.spacing.sm,
|
|
1283
|
+
backgroundColor: 'transparent',
|
|
1284
|
+
border: 'none',
|
|
1285
|
+
color: theme.colors.text,
|
|
1286
|
+
cursor: 'pointer',
|
|
1287
|
+
textAlign: 'left',
|
|
1288
|
+
fontSize: theme.fontSizes.sm,
|
|
1289
|
+
} }, "\uD83D\uDCC4 Document"))),
|
|
734
1290
|
React.createElement("button", { type: "button", onClick: isListening ? stopVoiceInput : startVoiceInput, disabled: isLoading, title: isListening ? "Stop recording" : "Start voice input", style: {
|
|
735
1291
|
position: 'absolute',
|
|
736
1292
|
right: '70px', // Position before the search button
|
|
@@ -738,7 +1294,6 @@ function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = 'Se
|
|
|
738
1294
|
transform: 'translateY(-50%)',
|
|
739
1295
|
padding: theme.spacing.sm,
|
|
740
1296
|
marginRight: theme.spacing.xs,
|
|
741
|
-
// backgroundColor: isListening ? theme.colors.error : theme.colors.primary,
|
|
742
1297
|
color: isListening ? theme.colors.primary : theme.colors.border,
|
|
743
1298
|
border: "none",
|
|
744
1299
|
borderRadius: theme.borderRadius,
|
|
@@ -750,7 +1305,7 @@ function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = 'Se
|
|
|
750
1305
|
width: "32px",
|
|
751
1306
|
height: "32px",
|
|
752
1307
|
} }, MIC_ICON_SVG),
|
|
753
|
-
React.createElement("button", { type: "submit", disabled: isLoading || !inputValue.trim(), style: {
|
|
1308
|
+
React.createElement("button", { type: "submit", disabled: isLoading || (!inputValue.trim() && !selectedFile), style: {
|
|
754
1309
|
position: 'absolute',
|
|
755
1310
|
right: theme.spacing.sm,
|
|
756
1311
|
top: '50%',
|
|
@@ -761,9 +1316,54 @@ function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = 'Se
|
|
|
761
1316
|
color: theme.colors.background,
|
|
762
1317
|
border: 'none',
|
|
763
1318
|
borderRadius: theme.borderRadius,
|
|
764
|
-
cursor: isLoading || !inputValue.trim() ? 'not-allowed' : 'pointer',
|
|
765
|
-
opacity: isLoading || !inputValue.trim() ? 0.5 : 1,
|
|
766
|
-
} }, isLoading ? 'Searching...' : 'Search'))
|
|
1319
|
+
cursor: isLoading || (!inputValue.trim() && !selectedFile) ? 'not-allowed' : 'pointer',
|
|
1320
|
+
opacity: isLoading || (!inputValue.trim() && !selectedFile) ? 0.5 : 1,
|
|
1321
|
+
} }, isLoading ? 'Searching...' : 'Search')),
|
|
1322
|
+
selectedFile && filePreview && (React.createElement("div", { style: {
|
|
1323
|
+
marginTop: theme.spacing.sm,
|
|
1324
|
+
padding: theme.spacing.sm,
|
|
1325
|
+
backgroundColor: theme.colors.surface,
|
|
1326
|
+
border: `1px solid ${theme.colors.border}`,
|
|
1327
|
+
borderRadius: theme.borderRadius,
|
|
1328
|
+
display: 'flex',
|
|
1329
|
+
alignItems: 'center',
|
|
1330
|
+
gap: theme.spacing.sm,
|
|
1331
|
+
} },
|
|
1332
|
+
selectedFile.type.startsWith('image/') ? (React.createElement("img", { src: filePreview, alt: "Preview", style: {
|
|
1333
|
+
width: '40px',
|
|
1334
|
+
height: '40px',
|
|
1335
|
+
objectFit: 'cover',
|
|
1336
|
+
borderRadius: theme.borderRadius,
|
|
1337
|
+
} })) : (React.createElement("div", { style: {
|
|
1338
|
+
width: '40px',
|
|
1339
|
+
height: '40px',
|
|
1340
|
+
backgroundColor: theme.colors.primary,
|
|
1341
|
+
borderRadius: theme.borderRadius,
|
|
1342
|
+
display: 'flex',
|
|
1343
|
+
alignItems: 'center',
|
|
1344
|
+
justifyContent: 'center',
|
|
1345
|
+
color: theme.colors.background,
|
|
1346
|
+
fontSize: theme.fontSizes.lg,
|
|
1347
|
+
} }, "\uD83D\uDCC4")),
|
|
1348
|
+
React.createElement("div", { style: { flex: 1, fontSize: theme.fontSizes.sm, color: theme.colors.text } },
|
|
1349
|
+
React.createElement("div", { style: { fontWeight: 'bold' } }, selectedFile.name),
|
|
1350
|
+
React.createElement("div", { style: { color: theme.colors.textSecondary } },
|
|
1351
|
+
(selectedFile.size / 1024 / 1024).toFixed(2),
|
|
1352
|
+
" MB")),
|
|
1353
|
+
React.createElement("button", { type: "button", onClick: removeFile, style: {
|
|
1354
|
+
padding: theme.spacing.xs,
|
|
1355
|
+
backgroundColor: 'transparent',
|
|
1356
|
+
border: 'none',
|
|
1357
|
+
color: theme.colors.textSecondary,
|
|
1358
|
+
cursor: 'pointer',
|
|
1359
|
+
borderRadius: theme.borderRadius,
|
|
1360
|
+
width: '24px',
|
|
1361
|
+
height: '24px',
|
|
1362
|
+
display: 'flex',
|
|
1363
|
+
alignItems: 'center',
|
|
1364
|
+
justifyContent: 'center',
|
|
1365
|
+
fontSize: '18px',
|
|
1366
|
+
}, title: "Remove file" }, "\u00D7")))),
|
|
767
1367
|
isOpen && displayMessages.length > 0 && (React.createElement("div", { style: {
|
|
768
1368
|
position: 'absolute',
|
|
769
1369
|
top: '100%',
|