reactbridge-sdk 0.2.14 → 0.2.16

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/index.js CHANGED
@@ -733,6 +733,38 @@ const TypingIndicator = ({ theme }) => (React.createElement("div", { style: {
733
733
  }
734
734
  }
735
735
  `))));
736
+ // Expandable Message Component with Show More functionality
737
+ const ExpandableMessage = ({ content, isUser, theme, isExpanded, onToggleExpand, }) => {
738
+ const characterLimit = 300;
739
+ const isLongMessage = content.length > characterLimit;
740
+ const displayText = isExpanded ? content : content.substring(0, characterLimit);
741
+ return (React.createElement("div", { style: {
742
+ maxWidth: "70%",
743
+ padding: theme.spacing.md,
744
+ borderRadius: theme.borderRadius,
745
+ backgroundColor: isUser
746
+ ? theme.colors.primary
747
+ : theme.colors.surface,
748
+ color: isUser ? "#ffffff" : theme.colors.text,
749
+ fontSize: theme.fontSizes.md,
750
+ boxShadow: theme.boxShadow,
751
+ wordWrap: "break-word",
752
+ whiteSpace: "pre-wrap",
753
+ overflowWrap: "break-word",
754
+ } },
755
+ React.createElement("div", { style: { marginBottom: isLongMessage && !isExpanded ? "8px" : "0" } }, displayText),
756
+ isLongMessage && (React.createElement("button", { onClick: onToggleExpand, style: {
757
+ background: "none",
758
+ border: "none",
759
+ color: isUser ? "#ffffff" : theme.colors.primary,
760
+ cursor: "pointer",
761
+ textDecoration: "underline",
762
+ padding: "0",
763
+ marginTop: isExpanded ? "8px" : "0",
764
+ fontSize: theme.fontSizes.sm,
765
+ fontWeight: "bold",
766
+ } }, isExpanded ? "Show less" : "Show more..."))));
767
+ };
736
768
  // Default styling constants for the widget wrapper
737
769
  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";
738
770
  function ReactBridgeChatbox({ onIntentDetected, currentContext, placeholder = "Type your message...", height = "500px", width = "100%", theme: themeOverride, renderMessage, onError,
@@ -762,7 +794,12 @@ toggleButtonClass = defaultToggleButtonClass, toggleButtonTitle = "Open chat ass
762
794
  const [isUploadMenuOpen, setIsUploadMenuOpen] = React.useState(false);
763
795
  const [selectedFile, setSelectedFile] = React.useState(null);
764
796
  const [filePreview, setFilePreview] = React.useState(null);
797
+ // Track expanded messages by ID
798
+ const [expandedMessages, setExpandedMessages] = React.useState(new Set());
799
+ // Track textarea height
800
+ const [textareaHeight, setTextareaHeight] = React.useState(40);
765
801
  const messagesEndRef = React.useRef(null);
802
+ const textareaRef = React.useRef(null);
766
803
  const containerRef = React.useRef(null);
767
804
  // Fallback styles for header
768
805
  const finalHeaderBgColor = headerBgColor || theme.colors.primary;
@@ -772,26 +809,89 @@ toggleButtonClass = defaultToggleButtonClass, toggleButtonTitle = "Open chat ass
772
809
  var _a;
773
810
  (_a = messagesEndRef.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ behavior: "smooth" });
774
811
  }, [messages]);
812
+ // Auto-scroll to bottom when widget opens
813
+ React.useEffect(() => {
814
+ if (isOpen && renderMode === "standard") {
815
+ setTimeout(() => {
816
+ var _a;
817
+ (_a = messagesEndRef.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ behavior: "smooth" });
818
+ }, 100);
819
+ }
820
+ }, [isOpen, renderMode]);
821
+ // Handle textarea height adjustment
822
+ const handleTextareaChange = React.useCallback((e) => {
823
+ const textarea = e.target;
824
+ setInputValue(textarea.value);
825
+ // Reset height to calculate scroll height
826
+ textarea.style.height = "auto";
827
+ const scrollHeight = textarea.scrollHeight;
828
+ const lineHeight = parseInt(window.getComputedStyle(textarea).lineHeight);
829
+ const maxHeight = lineHeight * 3; // 3 lines max
830
+ if (scrollHeight <= maxHeight) {
831
+ textarea.style.height = scrollHeight + "px";
832
+ setTextareaHeight(scrollHeight);
833
+ }
834
+ else {
835
+ textarea.style.height = maxHeight + "px";
836
+ textarea.style.overflowY = "auto";
837
+ setTextareaHeight(maxHeight);
838
+ }
839
+ }, []);
840
+ // Handle key down for Shift+Enter and Enter submission
841
+ const handleKeyDown = React.useCallback((e) => {
842
+ if (e.key === "Enter") {
843
+ if (e.shiftKey) {
844
+ // Shift+Enter: Allow new line (default behavior)
845
+ return;
846
+ }
847
+ else {
848
+ // Enter alone: Submit
849
+ e.preventDefault();
850
+ const form = e.currentTarget.closest("form");
851
+ if (form) {
852
+ form.dispatchEvent(new Event("submit", { bubbles: true, cancelable: true }));
853
+ }
854
+ }
855
+ }
856
+ }, []);
857
+ // Toggle message expansion
858
+ const toggleMessageExpansion = (messageId) => {
859
+ setExpandedMessages((prev) => {
860
+ const newSet = new Set(prev);
861
+ if (newSet.has(messageId)) {
862
+ newSet.delete(messageId);
863
+ }
864
+ else {
865
+ newSet.add(messageId);
866
+ }
867
+ return newSet;
868
+ });
869
+ };
775
870
  // Close upload menu and widget when clicking outside
776
871
  React.useEffect(() => {
777
872
  const handleClickOutside = (event) => {
778
873
  if (containerRef.current &&
779
874
  !containerRef.current.contains(event.target)) {
780
875
  setIsUploadMenuOpen(false);
781
- if (isOpen) {
876
+ if (isOpen && renderMode === "standard") {
782
877
  setIsOpen(false);
783
878
  }
784
879
  }
785
880
  };
786
881
  document.addEventListener("mousedown", handleClickOutside);
787
882
  return () => document.removeEventListener("mousedown", handleClickOutside);
788
- }, [isUploadMenuOpen, isOpen]);
883
+ }, [isUploadMenuOpen, isOpen, renderMode]);
789
884
  const handleSubmit = (e) => __awaiter(this, void 0, void 0, function* () {
790
885
  e.preventDefault();
791
886
  if ((!inputValue.trim() && !selectedFile) || isLoading)
792
887
  return;
793
888
  const query = inputValue.trim();
794
889
  setInputValue("");
890
+ setTextareaHeight(40);
891
+ if (textareaRef.current) {
892
+ textareaRef.current.style.height = "auto";
893
+ textareaRef.current.style.overflowY = "hidden";
894
+ }
795
895
  // Handle multimodal request
796
896
  if (selectedFile && filePreview) {
797
897
  if (filePreview.type === "image") {
@@ -864,22 +964,13 @@ toggleButtonClass = defaultToggleButtonClass, toggleButtonTitle = "Open chat ass
864
964
  // Don't render system messages in UI
865
965
  if (isSystem)
866
966
  return null;
967
+ const isExpanded = expandedMessages.has(message.id);
867
968
  return (React.createElement("div", { key: message.id, style: {
868
969
  display: "flex",
869
970
  justifyContent: isUser ? "flex-end" : "flex-start",
870
971
  marginBottom: theme.spacing.md,
871
972
  } },
872
- React.createElement("div", { style: {
873
- maxWidth: "70%",
874
- padding: theme.spacing.md,
875
- borderRadius: theme.borderRadius,
876
- backgroundColor: isUser
877
- ? theme.colors.primary
878
- : theme.colors.surface,
879
- color: isUser ? "#ffffff" : theme.colors.text,
880
- fontSize: theme.fontSizes.md,
881
- boxShadow: theme.boxShadow,
882
- } }, message.content)));
973
+ React.createElement(ExpandableMessage, { content: message.content, isUser: isUser, theme: theme, isExpanded: isExpanded, onToggleExpand: () => toggleMessageExpansion(message.id) })));
883
974
  };
884
975
  // --- RENDER LOGIC FOR 'BASIC' MODE (Original Behavior) ---
885
976
  if (renderMode === "basic") {
@@ -913,9 +1004,9 @@ toggleButtonClass = defaultToggleButtonClass, toggleButtonTitle = "Open chat ass
913
1004
  React.createElement("div", { style: {
914
1005
  display: "flex",
915
1006
  gap: theme.spacing.sm,
916
- alignItems: "center",
1007
+ alignItems: "flex-end",
917
1008
  } },
918
- React.createElement("input", { type: "text", value: inputValue, onChange: (e) => setInputValue(e.target.value), placeholder: placeholder, disabled: isLoading, style: {
1009
+ React.createElement("textarea", { ref: textareaRef, value: inputValue, onChange: handleTextareaChange, onKeyDown: handleKeyDown, placeholder: placeholder, disabled: isLoading, style: {
919
1010
  flex: 1,
920
1011
  padding: theme.spacing.sm,
921
1012
  fontSize: theme.fontSizes.md,
@@ -924,6 +1015,11 @@ toggleButtonClass = defaultToggleButtonClass, toggleButtonTitle = "Open chat ass
924
1015
  backgroundColor: theme.colors.background,
925
1016
  color: theme.colors.text,
926
1017
  outline: "none",
1018
+ fontFamily: "inherit",
1019
+ resize: "none",
1020
+ minHeight: "40px",
1021
+ maxHeight: "120px",
1022
+ height: `${textareaHeight}px`,
927
1023
  } }),
928
1024
  React.createElement("button", { type: "button", onClick: () => setIsUploadMenuOpen(!isUploadMenuOpen), disabled: isLoading, title: "Attach file", style: {
929
1025
  padding: theme.spacing.sm,
@@ -1114,9 +1210,9 @@ toggleButtonClass = defaultToggleButtonClass, toggleButtonTitle = "Open chat ass
1114
1210
  React.createElement("div", { style: {
1115
1211
  display: "flex",
1116
1212
  gap: theme.spacing.sm,
1117
- alignItems: "center",
1213
+ alignItems: "flex-end",
1118
1214
  } },
1119
- React.createElement("input", { type: "text", value: inputValue, onChange: (e) => setInputValue(e.target.value), placeholder: placeholder, disabled: isLoading, style: {
1215
+ React.createElement("textarea", { ref: textareaRef, value: inputValue, onChange: handleTextareaChange, onKeyDown: handleKeyDown, placeholder: placeholder, disabled: isLoading, style: {
1120
1216
  flex: 1,
1121
1217
  padding: theme.spacing.sm,
1122
1218
  fontSize: theme.fontSizes.md,
@@ -1125,6 +1221,11 @@ toggleButtonClass = defaultToggleButtonClass, toggleButtonTitle = "Open chat ass
1125
1221
  backgroundColor: theme.colors.background,
1126
1222
  color: theme.colors.text,
1127
1223
  outline: "none",
1224
+ fontFamily: "inherit",
1225
+ resize: "none",
1226
+ minHeight: "40px",
1227
+ maxHeight: "120px",
1228
+ height: `${textareaHeight}px`,
1128
1229
  } }),
1129
1230
  React.createElement("button", { type: "button", onClick: () => setIsUploadMenuOpen(!isUploadMenuOpen), disabled: isLoading, title: "Attach file", style: {
1130
1231
  padding: theme.spacing.sm,
@@ -2306,8 +2407,9 @@ const AnalyticsDrawer = ({ isOpen, onClose, configs, isLoading, theme, onDirecti
2306
2407
  };
2307
2408
 
2308
2409
  // Analytics Icon SVG
2309
- const ANALYTICS_ICON_SVG = (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "1em", height: "1em", fill: "currentColor" },
2310
- React.createElement("path", { d: "M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z" })));
2410
+ const ANALYTICS_ICON_SVG = (React.createElement(React.Fragment, null,
2411
+ React.createElement("svg", { width: "36", height: "36", viewBox: "0 0 40 40", fill: "currentColor", xmlns: "http://www.w3.org/2000/svg" },
2412
+ React.createElement("path", { d: "M10 10 L 35 20 L 10 30 L 15 20 Z", fill: "currentColor" }))));
2311
2413
  const AnalyticsWidget = ({ position = "bottom-right", theme: customTheme, onDirectiveAction, }) => {
2312
2414
  const { theme: contextTheme } = useReactBridgeContext();
2313
2415
  const theme = customTheme || contextTheme;