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