@contentgrowth/llm-service 1.0.7 → 1.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -177,10 +177,17 @@ interface ChatInputAreaProps {
177
177
  value?: string;
178
178
  onChange?: (e: React.ChangeEvent<HTMLTextAreaElement>) => void;
179
179
  defaultInputMode?: 'text' | 'voice';
180
+ hideVoiceButton?: boolean;
181
+ inputMode?: 'none' | 'text' | 'search' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal';
180
182
  }
181
183
  interface ChatInputAreaHandle {
182
184
  focus: () => void;
183
185
  setValue: (value: string) => void;
186
+ getSelection: () => {
187
+ start: number;
188
+ end: number;
189
+ } | null;
190
+ replaceSelection: (text: string) => void;
184
191
  }
185
192
  declare const ChatInputArea: React.ForwardRefExoticComponent<ChatInputAreaProps & React.RefAttributes<ChatInputAreaHandle>>;
186
193
 
@@ -192,6 +199,7 @@ interface TapToTalkProps {
192
199
  tooltip?: string;
193
200
  onFocusTarget?: () => void;
194
201
  accentColor?: string;
202
+ leftAction?: React.ReactNode;
195
203
  }
196
204
  declare const TapToTalk: React.FC<TapToTalkProps>;
197
205
 
@@ -177,10 +177,17 @@ interface ChatInputAreaProps {
177
177
  value?: string;
178
178
  onChange?: (e: React.ChangeEvent<HTMLTextAreaElement>) => void;
179
179
  defaultInputMode?: 'text' | 'voice';
180
+ hideVoiceButton?: boolean;
181
+ inputMode?: 'none' | 'text' | 'search' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal';
180
182
  }
181
183
  interface ChatInputAreaHandle {
182
184
  focus: () => void;
183
185
  setValue: (value: string) => void;
186
+ getSelection: () => {
187
+ start: number;
188
+ end: number;
189
+ } | null;
190
+ replaceSelection: (text: string) => void;
184
191
  }
185
192
  declare const ChatInputArea: React.ForwardRefExoticComponent<ChatInputAreaProps & React.RefAttributes<ChatInputAreaHandle>>;
186
193
 
@@ -192,6 +199,7 @@ interface TapToTalkProps {
192
199
  tooltip?: string;
193
200
  onFocusTarget?: () => void;
194
201
  accentColor?: string;
202
+ leftAction?: React.ReactNode;
195
203
  }
196
204
  declare const TapToTalk: React.FC<TapToTalkProps>;
197
205
 
@@ -437,7 +437,9 @@ var ChatInputArea = forwardRef(({
437
437
  placeholder,
438
438
  value,
439
439
  onChange,
440
- defaultInputMode = "text"
440
+ defaultInputMode = "text",
441
+ hideVoiceButton = false,
442
+ inputMode: inputModeProp
441
443
  }, ref) => {
442
444
  var _a, _b, _c, _d;
443
445
  const [internalMessage, setInternalMessage] = useState3("");
@@ -487,6 +489,7 @@ var ChatInputArea = forwardRef(({
487
489
  const textareaRef = useRef3(null);
488
490
  const measurementRef = useRef3(null);
489
491
  const pendingSelectionRef = useRef3(null);
492
+ const lastSelectionRef = useRef3(null);
490
493
  const isControlled = value !== void 0;
491
494
  const message = isControlled ? value : internalMessage;
492
495
  const messageRef = useRef3(message);
@@ -581,11 +584,39 @@ var ChatInputArea = forwardRef(({
581
584
  });
582
585
  useImperativeHandle(ref, () => ({
583
586
  focus: () => {
584
- var _a2;
585
- (_a2 = textareaRef.current) == null ? void 0 : _a2.focus();
587
+ const textarea = textareaRef.current;
588
+ if (textarea) {
589
+ textarea.focus();
590
+ if (lastSelectionRef.current) {
591
+ textarea.setSelectionRange(
592
+ lastSelectionRef.current.start,
593
+ lastSelectionRef.current.end
594
+ );
595
+ }
596
+ }
586
597
  },
587
598
  setValue: (newValue) => {
588
599
  triggerChange(newValue);
600
+ },
601
+ getSelection: () => {
602
+ const textarea = textareaRef.current;
603
+ if (textarea && document.activeElement === textarea) {
604
+ return { start: textarea.selectionStart, end: textarea.selectionEnd };
605
+ }
606
+ return lastSelectionRef.current;
607
+ },
608
+ replaceSelection: (text) => {
609
+ const selection = lastSelectionRef.current;
610
+ const currentVal = messageRef.current || "";
611
+ if (selection && selection.start !== selection.end) {
612
+ const before = currentVal.substring(0, selection.start);
613
+ const after = currentVal.substring(selection.end);
614
+ const newText = before + text + after;
615
+ triggerChange(newText);
616
+ lastSelectionRef.current = null;
617
+ } else {
618
+ insertTextAtCursor(text);
619
+ }
589
620
  }
590
621
  }));
591
622
  const handleSubmit = (e) => {
@@ -674,7 +705,7 @@ var ChatInputArea = forwardRef(({
674
705
  logs.length === 0 && /* @__PURE__ */ jsx6("div", { children: "No logs yet..." })
675
706
  ] }),
676
707
  /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2", children: [
677
- voiceConfig && /* @__PURE__ */ jsx6(
708
+ voiceConfig && !hideVoiceButton && /* @__PURE__ */ jsx6(
678
709
  VoiceInputButton,
679
710
  {
680
711
  voiceConfig,
@@ -719,12 +750,22 @@ var ChatInputArea = forwardRef(({
719
750
  setIsFocused(true);
720
751
  setVoiceError(null);
721
752
  },
722
- onBlur: () => setIsFocused(false),
753
+ onBlur: () => {
754
+ setIsFocused(false);
755
+ const textarea = textareaRef.current;
756
+ if (textarea) {
757
+ lastSelectionRef.current = {
758
+ start: textarea.selectionStart,
759
+ end: textarea.selectionEnd
760
+ };
761
+ }
762
+ },
723
763
  placeholder: getPlaceholder(),
724
764
  disabled: isInputDisabled,
725
765
  readOnly: !!voiceTrigger || isTranscribing,
726
766
  rows: 1,
727
- className: `flex-grow px-4 py-2 outline-none text-gray-700 placeholder-gray-500 resize-none leading-6 w-full ${isInputDisabled ? "bg-gray-100 cursor-not-allowed" : "bg-transparent"} ${voiceTrigger || isTranscribing ? "cursor-default" : ""}`
767
+ className: `flex-grow px-4 py-2 outline-none text-gray-700 placeholder-gray-500 resize-none leading-6 w-full ${isInputDisabled ? "bg-gray-100 cursor-not-allowed" : "bg-transparent"} ${voiceTrigger || isTranscribing ? "cursor-default" : ""}`,
768
+ ...inputModeProp ? { inputMode: inputModeProp } : {}
728
769
  }
729
770
  ),
730
771
  /* @__PURE__ */ jsxs4("div", { className: "relative mx-2 flex-shrink-0", children: [
@@ -801,7 +842,8 @@ var TapToTalk = ({
801
842
  disabled = false,
802
843
  tooltip = "Tap to speak",
803
844
  onFocusTarget,
804
- accentColor = "bg-emerald-600"
845
+ accentColor = "bg-emerald-600",
846
+ leftAction
805
847
  }) => {
806
848
  var _a;
807
849
  const globalConfig = useChatConfig();
@@ -992,23 +1034,26 @@ var TapToTalk = ({
992
1034
  logs.map((log, i) => /* @__PURE__ */ jsx7("div", { className: "mb-0.5 border-b border-gray-700/50 pb-0.5 break-all", children: log }, i)),
993
1035
  logs.length === 0 && /* @__PURE__ */ jsx7("div", { children: "No logs yet..." })
994
1036
  ] }),
995
- /* @__PURE__ */ jsxs5(
996
- "button",
997
- {
998
- ...handlers,
999
- disabled: disabled || isTranscribing && !isListening,
1000
- className: `flex items-center justify-center gap-3 px-6 py-3 rounded-xl transition-all duration-300 w-full font-medium shadow-md touch-none select-none
1037
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2 w-full", children: [
1038
+ leftAction,
1039
+ /* @__PURE__ */ jsxs5(
1040
+ "button",
1041
+ {
1042
+ ...handlers,
1043
+ disabled: disabled || isTranscribing && !isListening,
1044
+ className: `flex items-center justify-center gap-3 px-6 py-3 rounded-xl transition-all duration-300 flex-1 font-medium shadow-md touch-none select-none
1001
1045
  ${bgColor} text-white
1002
1046
  ${disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"}
1003
1047
  ${className}`,
1004
- title: label,
1005
- children: [
1006
- /* @__PURE__ */ jsx7("div", { className: "flex items-center justify-center shrink-0", children: Icon }),
1007
- /* @__PURE__ */ jsx7("span", { className: "truncate", children: label }),
1008
- errorMsg && /* @__PURE__ */ jsx7("span", { className: "text-[10px] bg-white/20 px-1.5 py-0.5 rounded text-red-100 animate-in fade-in slide-in-from-right-1", children: errorMsg })
1009
- ]
1010
- }
1011
- )
1048
+ title: label,
1049
+ children: [
1050
+ /* @__PURE__ */ jsx7("div", { className: "flex items-center justify-center shrink-0", children: Icon }),
1051
+ /* @__PURE__ */ jsx7("span", { className: "truncate", children: label }),
1052
+ errorMsg && /* @__PURE__ */ jsx7("span", { className: "text-[10px] bg-white/20 px-1.5 py-0.5 rounded text-red-100 animate-in fade-in slide-in-from-right-1", children: errorMsg })
1053
+ ]
1054
+ }
1055
+ )
1056
+ ] })
1012
1057
  ] });
1013
1058
  };
1014
1059