@sampleapp.ai/sdk 1.0.25 → 1.0.27

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.
@@ -12,7 +12,6 @@ var __rest = (this && this.__rest) || function (s, e) {
12
12
  };
13
13
  import React from "react";
14
14
  import { useState, useEffect, useRef, forwardRef } from "react";
15
- import { motion, AnimatePresence } from "framer-motion";
16
15
  import { Textarea } from "../ui/textarea";
17
16
  export const TypingTextarea = forwardRef((_a, ref) => {
18
17
  var { texts, typingSpeed = 30, deletingSpeed = 15, delayAfterText = 800, onSubmit, isStreaming = false, className = "", placeholderClassName = "", value, onChange, onFocus, onBlur, onKeyDown, onPaste, placeholder: originalPlaceholder, rows = 1 } = _a, props = __rest(_a, ["texts", "typingSpeed", "deletingSpeed", "delayAfterText", "onSubmit", "isStreaming", "className", "placeholderClassName", "value", "onChange", "onFocus", "onBlur", "onKeyDown", "onPaste", "placeholder", "rows"]);
@@ -22,11 +21,11 @@ export const TypingTextarea = forwardRef((_a, ref) => {
22
21
  const [isWaiting, setIsWaiting] = useState(false);
23
22
  const [showTabHint, setShowTabHint] = useState(false);
24
23
  const [isPausing, setIsPausing] = useState(false);
24
+ const [isAnimating, setIsAnimating] = useState(false);
25
25
  const localRef = useRef(null);
26
26
  const textareaRef = ref || localRef;
27
27
  const currentText = texts[textIndex];
28
28
  const isEmpty = value === "" || value === undefined;
29
- // const isFullTextDisplayed = displayText === currentText && !isDeleting;
30
29
  // Handle animation only when textarea is empty
31
30
  useEffect(() => {
32
31
  if (!isEmpty)
@@ -37,14 +36,16 @@ export const TypingTextarea = forwardRef((_a, ref) => {
37
36
  setIsWaiting(false);
38
37
  setIsPausing(true);
39
38
  setShowTabHint(true);
39
+ setIsAnimating(true);
40
40
  }, delayAfterText);
41
41
  return () => clearTimeout(timeout);
42
42
  }
43
43
  if (isPausing) {
44
- // Show tab hint for 3 seconds with fade animation
44
+ // Show tab hint for 3 seconds
45
45
  timeout = setTimeout(() => {
46
- setShowTabHint(false);
46
+ setIsAnimating(false);
47
47
  setTimeout(() => {
48
+ setShowTabHint(false);
48
49
  setIsPausing(false);
49
50
  setIsDeleting(true);
50
51
  }, 300); // Wait for fade out animation
@@ -120,25 +121,30 @@ export const TypingTextarea = forwardRef((_a, ref) => {
120
121
  paddingRight: "4px",
121
122
  paddingTop: "0",
122
123
  paddingBottom: "0",
123
- marginTop: "4px",
124
+ marginTop: "5px",
124
125
  } },
125
- React.createElement("p", { style: Object.assign({ color: "#a1a1aa", fontWeight: "500", lineHeight: "1.5" }, (placeholderClassName ? {} : {})) },
126
+ React.createElement("p", { style: Object.assign({ color: "#a1a1aa", fontWeight: "500", lineHeight: "1.25" }, (placeholderClassName ? {} : {})) },
126
127
  displayText,
127
- React.createElement(AnimatePresence, null, showTabHint && (React.createElement(motion.span, { initial: { opacity: 0, scale: 0.8 }, animate: { opacity: 1, scale: 1 }, exit: { opacity: 0, scale: 0.8 }, transition: { duration: 0.3 }, style: {
128
+ React.createElement("span", { style: {
128
129
  fontSize: "12px",
129
- color: "#d1d5db", // zinc-300 for dark mode
130
- backgroundColor: "#27272a", // zinc-800 for dark mode
130
+ color: "#d1d5db",
131
+ backgroundColor: "#27272a",
131
132
  paddingLeft: "6px",
132
133
  paddingRight: "6px",
133
134
  paddingTop: "2px",
134
135
  paddingBottom: "2px",
135
136
  borderRadius: "8px",
136
- border: "1px solid #3f3f46", // zinc-700 for dark mode
137
+ border: "1px solid #3f3f46",
137
138
  alignItems: "center",
138
139
  marginLeft: "8px",
139
140
  display: "inline-flex",
140
141
  whiteSpace: "nowrap",
141
- } }, "Tab to select")))))),
142
+ opacity: isAnimating ? 1 : 0,
143
+ transform: isAnimating ? "scale(1)" : "scale(0.8)",
144
+ transition: "opacity 0.3s ease, transform 0.3s ease",
145
+ visibility: showTabHint ? "visible" : "hidden",
146
+ verticalAlign: "middle",
147
+ } }, "Tab to select")))),
142
148
  React.createElement(Textarea, Object.assign({ ref: textareaRef, placeholder: originalPlaceholder, style: className ? {} : {}, value: value, onFocus: onFocus, onBlur: onBlur, onChange: onChange, onKeyDown: handleKeyDown, onPaste: onPaste, rows: rows }, props))));
143
149
  });
144
150
  TypingTextarea.displayName = "TypingTextarea";
@@ -1,26 +1,13 @@
1
1
  "use client";
2
2
  import React from "react";
3
3
  import { Button } from "../ui/button";
4
- import { VoiceIcon } from "./voice-button/voice-icon";
5
- export const VoiceButton = ({ isRecording, isTranscribing, onVoiceRecording, playgroundUid, // eslint-disable-line @typescript-eslint/no-unused-vars
6
- isLoggedIn = false, }) => {
4
+ import { VoiceIcon } from "../icons";
5
+ export const VoiceButton = ({ isRecording, isTranscribing, onVoiceRecording, }) => {
7
6
  // Don't show voice button for statsig playground
8
7
  // if (playgroundUid === "statsig") {
9
8
  // return null;
10
9
  // }
11
- const getTooltipText = () => {
12
- if (isTranscribing) {
13
- return "Transcribing your voice...";
14
- }
15
- if (isRecording) {
16
- return "Click to stop recording";
17
- }
18
- if (isLoggedIn) {
19
- return "Voice Mode – Build with voice (Ctrl/Cmd + /)";
20
- }
21
- return "Sign up to use voice mode";
22
- };
23
- return (React.createElement(Button, { size: "sm", variant: "ghostOutline", style: Object.assign(Object.assign({ height: "32px", paddingLeft: "8px", paddingRight: "8px", fontSize: "12px", fontWeight: "500", transition: "all 0.2s ease-in-out" }, (isRecording && {
10
+ return (React.createElement(Button, { size: "icon", variant: "outline", style: Object.assign(Object.assign({ height: "32px", paddingLeft: "8px", paddingRight: "8px", fontSize: "12px", fontWeight: "500", transition: "all 0.2s ease-in-out" }, (isRecording && {
24
11
  backgroundColor: "#ef4444", // red-500
25
12
  borderColor: "#ef4444",
26
13
  boxShadow: "0 10px 15px -3px rgba(239, 68, 68, 0.25)",
@@ -31,12 +18,7 @@ isLoggedIn = false, }) => {
31
18
  boxShadow: "0 10px 15px -3px rgba(59, 130, 246, 0.25)",
32
19
  color: "white",
33
20
  })), onClick: () => {
34
- if (isLoggedIn && !isTranscribing) {
35
- onVoiceRecording();
36
- }
37
- else if (!isLoggedIn) {
38
- window.location.href = "/sign-up";
39
- }
21
+ onVoiceRecording();
40
22
  }, disabled: isTranscribing },
41
23
  React.createElement(VoiceIcon, { isRecording: isRecording, isTranscribing: isTranscribing })));
42
24
  };
@@ -2,22 +2,36 @@
2
2
  /* eslint-disable @next/next/no-img-element */
3
3
  import React from "react";
4
4
  import { useState, useRef, useEffect, useMemo } from "react";
5
- import { ArrowUp, Loader2, CircleStop } from "lucide-react";
6
- import { TypingTextarea } from "./chat-bar/typing-textarea";
7
5
  import { Textarea } from "./ui/textarea";
8
- import { VoiceButton } from "./chat-bar/voice-button";
9
- import { VoiceOverlay } from "./chat-bar/voice-overlay";
10
6
  import { Button } from "./ui/button";
11
7
  import { getTheme } from "../themes";
8
+ import { LoaderIcon, ArrowUpIcon } from "./icons";
9
+ import { TypingTextarea } from "./chat-bar/typing-textarea";
10
+ import { VoiceButton } from "./chat-bar/voice-button";
11
+ // Default fallback color scheme
12
+ const DEFAULT_COLOR_SCHEME = {
13
+ gradient: "linear-gradient(45deg, #3b82f6, #8b5cf6, #ec4899)",
14
+ shadow: {
15
+ dark: "rgba(0, 0, 0, 0.2)",
16
+ },
17
+ };
12
18
  const getColorScheme = (themeName, playgroundUid) => {
13
- // If theme is provided, use it directly
14
- if (themeName) {
15
- return getTheme(themeName);
19
+ try {
20
+ // If theme is provided, use it directly
21
+ if (themeName) {
22
+ const theme = getTheme(themeName);
23
+ return theme || DEFAULT_COLOR_SCHEME;
24
+ }
25
+ // Use default theme
26
+ const defaultTheme = getTheme();
27
+ return defaultTheme || DEFAULT_COLOR_SCHEME;
28
+ }
29
+ catch (error) {
30
+ console.warn("Theme system error, using fallback:", error);
31
+ return DEFAULT_COLOR_SCHEME;
16
32
  }
17
- // Use default theme
18
- return getTheme();
19
33
  };
20
- export const ChatBar = ({ query, placeholder = "Ask anything...", setQuery, onSubmit, isStreaming, height, hasPendingEnv, playgroundUid, hasTypingAnimation = false, isSubmitting, onCancel, typingTexts = [
34
+ export const ChatBar = ({ placeholder = "Ask anything...", onSubmit, playgroundUid, isSubmitting, typingTexts = [
21
35
  "Build me an AI chatbot application using OpenAI API",
22
36
  "Build me an ecommerce website using Stripe API",
23
37
  "Build me a price tracking tool using AgentQL API",
@@ -25,31 +39,43 @@ export const ChatBar = ({ query, placeholder = "Ask anything...", setQuery, onSu
25
39
  "Build me a weather forecasting app using OpenWeather API",
26
40
  "Build me a SMS notification system using Twilio API",
27
41
  "Build me a travel booking platform using Skyscanner API",
28
- // "Build me an inventory management system using AWS S3",
29
- // "Build me a social media platform using Firebase",
30
- // "Build me a project management tool using Trello API",
31
- ], shouldFocusOnMount = true, showModelSelector = true, projectUid, theme, }) => {
42
+ ], shouldFocusOnMount = true, showModelSelector = true, projectUid, theme, height = "auto", // Add default for required height prop
43
+ deepgramApiKey, }) => {
44
+ var _a;
32
45
  const [isFocused, setIsFocused] = useState(true);
33
46
  const [isRecording, setIsRecording] = useState(false);
34
47
  const [isTranscribing, setIsTranscribing] = useState(false);
35
48
  const [, setShowVoiceOverlay] = useState(false);
36
49
  const [recordingTimeout, setRecordingTimeout] = useState(null);
37
50
  const [recordingStartTime, setRecordingStartTime] = useState(null);
51
+ const [query, setQuery] = useState("");
38
52
  const mediaRecorderRef = useRef(null);
39
53
  const audioChunksRef = useRef([]);
40
- const fileInputRef = useRef(null);
41
54
  const textareaRef = useRef(null);
42
55
  const [isMounted, setIsMounted] = useState(false);
43
- // Get color scheme for gradient border
44
- const colorScheme = useMemo(() => getColorScheme(theme, playgroundUid), [theme, playgroundUid]);
56
+ // Get color scheme for gradient border with error handling
57
+ const colorScheme = useMemo(() => {
58
+ try {
59
+ return getColorScheme(theme, playgroundUid);
60
+ }
61
+ catch (error) {
62
+ console.warn("Error getting color scheme:", error);
63
+ return DEFAULT_COLOR_SCHEME;
64
+ }
65
+ }, [theme, playgroundUid]);
45
66
  useEffect(() => {
46
67
  setIsMounted(true);
47
68
  }, []);
48
69
  useEffect(() => {
49
70
  // Focus and select all text in the textarea when component mounts
50
71
  if (shouldFocusOnMount && textareaRef.current && isMounted) {
51
- textareaRef.current.focus();
52
- textareaRef.current.select();
72
+ try {
73
+ textareaRef.current.focus();
74
+ textareaRef.current.select();
75
+ }
76
+ catch (error) {
77
+ console.warn("Focus error:", error);
78
+ }
53
79
  }
54
80
  }, [isMounted, shouldFocusOnMount]);
55
81
  const handleFocus = () => {
@@ -62,11 +88,16 @@ export const ChatBar = ({ query, placeholder = "Ask anything...", setQuery, onSu
62
88
  const adjustTextareaHeight = () => {
63
89
  const textarea = textareaRef.current;
64
90
  if (textarea) {
65
- // Reset height to auto to get the correct scrollHeight
66
- textarea.style.height = "auto";
67
- // Set new height based on scrollHeight, with a maximum of 200px
68
- const newHeight = Math.min(textarea.scrollHeight, 200);
69
- textarea.style.height = `${newHeight}px`;
91
+ try {
92
+ // Reset height to auto to get the correct scrollHeight
93
+ textarea.style.height = "auto";
94
+ // Set new height based on scrollHeight, with a maximum of 200px
95
+ const newHeight = Math.min(textarea.scrollHeight, 200);
96
+ textarea.style.height = `${newHeight}px`;
97
+ }
98
+ catch (error) {
99
+ console.warn("Textarea height adjustment error:", error);
100
+ }
70
101
  }
71
102
  };
72
103
  // Update height whenever query changes
@@ -113,16 +144,15 @@ export const ChatBar = ({ query, placeholder = "Ask anything...", setQuery, onSu
113
144
  setShowVoiceOverlay(false);
114
145
  };
115
146
  }, [recordingTimeout, isRecording]);
116
- const handleVoiceOverlayDismiss = () => {
117
- // Only allow dismissing during recording, not transcribing
118
- if (isTranscribing)
119
- return;
120
- if (isRecording) {
121
- // Stop recording if currently recording
122
- stopRecording();
123
- }
124
- setShowVoiceOverlay(false);
125
- };
147
+ // const handleVoiceOverlayDismiss = () => {
148
+ // // Only allow dismissing during recording, not transcribing
149
+ // if (isTranscribing) return;
150
+ // if (isRecording) {
151
+ // // Stop recording if currently recording
152
+ // stopRecording();
153
+ // }
154
+ // setShowVoiceOverlay(false);
155
+ // };
126
156
  const stopRecording = async () => {
127
157
  if (mediaRecorderRef.current && isRecording) {
128
158
  // Check minimum recording duration (1 second)
@@ -178,7 +208,11 @@ export const ChatBar = ({ query, placeholder = "Ask anything...", setQuery, onSu
178
208
  // Send to backend for transcription
179
209
  const formData = new FormData();
180
210
  formData.append("audio", audioBlob, "recording.wav");
181
- const response = await fetch("/api/voice/transcribe", {
211
+ // Add Deepgram API key if provided
212
+ if (deepgramApiKey) {
213
+ formData.append("deepgramApiKey", deepgramApiKey);
214
+ }
215
+ const response = await fetch(`/api/voice/transcribe`, {
182
216
  method: "POST",
183
217
  body: formData,
184
218
  });
@@ -362,8 +396,26 @@ export const ChatBar = ({ query, placeholder = "Ask anything...", setQuery, onSu
362
396
  }
363
397
  }
364
398
  };
399
+ const handleSubmit = (e) => {
400
+ e.preventDefault();
401
+ if (!query.trim()) {
402
+ return;
403
+ }
404
+ try {
405
+ if (playgroundUid) {
406
+ const encodedQuery = encodeURIComponent(query.trim());
407
+ const url = `https://${playgroundUid}.sampleapp.ai?q=${encodedQuery}`;
408
+ window.open(url, "_blank");
409
+ }
410
+ if (onSubmit) {
411
+ onSubmit(e);
412
+ }
413
+ }
414
+ catch (error) {
415
+ console.error("Submit error:", error);
416
+ }
417
+ };
365
418
  return (React.createElement("div", null,
366
- React.createElement(VoiceOverlay, { isRecording: isRecording, isTranscribing: isTranscribing, onDismiss: handleVoiceOverlayDismiss }),
367
419
  React.createElement("div", { style: {
368
420
  position: "relative",
369
421
  padding: "2px",
@@ -373,7 +425,7 @@ export const ChatBar = ({ query, placeholder = "Ask anything...", setQuery, onSu
373
425
  marginRight: "auto",
374
426
  } },
375
427
  React.createElement("div", { style: {
376
- backgroundColor: colorScheme.shadow.dark,
428
+ backgroundColor: ((_a = colorScheme.shadow) === null || _a === void 0 ? void 0 : _a.dark) || "rgba(0, 0, 0, 0.2)",
377
429
  position: "absolute",
378
430
  top: "0",
379
431
  right: "0",
@@ -386,7 +438,7 @@ export const ChatBar = ({ query, placeholder = "Ask anything...", setQuery, onSu
386
438
  pointerEvents: "none",
387
439
  } }),
388
440
  React.createElement("div", { style: {
389
- background: colorScheme.gradient,
441
+ background: colorScheme.gradient || DEFAULT_COLOR_SCHEME.gradient,
390
442
  backgroundSize: "400% 400%",
391
443
  position: "absolute",
392
444
  top: "0",
@@ -402,7 +454,7 @@ export const ChatBar = ({ query, placeholder = "Ask anything...", setQuery, onSu
402
454
  animation: "gradient-bg 5s ease infinite",
403
455
  } }),
404
456
  React.createElement("div", { style: {
405
- background: colorScheme.gradient,
457
+ background: colorScheme.gradient || DEFAULT_COLOR_SCHEME.gradient,
406
458
  backgroundSize: "400% 400%",
407
459
  position: "absolute",
408
460
  top: "0",
@@ -437,7 +489,7 @@ export const ChatBar = ({ query, placeholder = "Ask anything...", setQuery, onSu
437
489
  paddingTop: "4px",
438
490
  paddingBottom: "4px",
439
491
  } },
440
- hasTypingAnimation && typingTexts.length > 0 ? (React.createElement(TypingTextarea, { texts: typingTexts, ref: textareaRef, style: {
492
+ typingTexts.length > 0 ? (React.createElement(TypingTextarea, { texts: typingTexts, ref: textareaRef, style: {
441
493
  flex: 1,
442
494
  width: "100%",
443
495
  border: "none",
@@ -458,14 +510,15 @@ export const ChatBar = ({ query, placeholder = "Ask anything...", setQuery, onSu
458
510
  marginTop: "4px",
459
511
  color: "#f4f4f5",
460
512
  fontFamily: "inherit",
513
+ height: height,
461
514
  }, value: query, onFocus: handleFocus, onBlur: handleBlur, onChange: (e) => setQuery(e.target.value), onSubmit: (e) => {
462
515
  // Prevent submission if recording
463
516
  if (isRecording || isTranscribing) {
464
517
  e.preventDefault();
465
518
  return;
466
519
  }
467
- onSubmit(e);
468
- }, isStreaming: isStreaming, rows: 1 })) : (React.createElement(Textarea, { ref: textareaRef, placeholder: placeholder, style: {
520
+ handleSubmit(e);
521
+ }, rows: 1 })) : (React.createElement(Textarea, { ref: textareaRef, placeholder: placeholder, style: {
469
522
  flex: 1,
470
523
  width: "100%",
471
524
  border: "none",
@@ -486,36 +539,22 @@ export const ChatBar = ({ query, placeholder = "Ask anything...", setQuery, onSu
486
539
  marginTop: "4px",
487
540
  color: "#f4f4f5",
488
541
  fontFamily: "inherit",
542
+ height: height,
489
543
  }, value: query, onFocus: handleFocus, onBlur: handleBlur, onChange: (e) => setQuery(e.target.value), onKeyDown: (e) => {
490
544
  if (e.key === "Enter") {
491
545
  if (e.shiftKey) {
492
546
  return;
493
547
  }
494
548
  e.preventDefault();
495
- if (isStreaming) {
496
- return;
497
- }
498
- onSubmit(e);
549
+ handleSubmit(e);
499
550
  }
500
551
  }, rows: 1 })),
501
- React.createElement("div", null,
502
- React.createElement(VoiceButton, { isRecording: isRecording, isTranscribing: isTranscribing, onVoiceRecording: handleVoiceRecording, playgroundUid: playgroundUid }),
552
+ React.createElement("div", { style: { display: "flex", flexDirection: "row", gap: "4px" } },
553
+ React.createElement(VoiceButton, { isRecording: isRecording, isTranscribing: isTranscribing, onVoiceRecording: handleVoiceRecording }),
503
554
  React.createElement(Button, { style: {
504
555
  height: "32px",
505
556
  width: "32px",
506
- borderRadius: "6px",
507
- }, disabled: query.length === 0 || isSubmitting || hasPendingEnv, variant: isStreaming ? "outline" : "default", onClick: (e) => {
508
- if (isStreaming && onCancel) {
509
- onCancel();
510
- }
511
- else {
512
- onSubmit(e);
513
- }
514
- } }, isSubmitting ? (React.createElement(Loader2, { style: {
515
- height: "20px",
516
- width: "20px",
517
- animation: "spin 1s linear infinite",
518
- } })) : isStreaming ? (React.createElement(CircleStop, { style: { height: "24px", width: "24px" } })) : (React.createElement(ArrowUp, { style: { height: "20px", width: "20px" } }))))),
557
+ }, disabled: query.length === 0 || isSubmitting, variant: "secondary", onClick: handleSubmit, size: "icon" }, isSubmitting ? (React.createElement(LoaderIcon, { size: 20, style: { animation: "spin 1s linear infinite" } })) : (React.createElement(ArrowUpIcon, { style: { width: "20px", height: "20px" } }))))),
519
558
  React.createElement("div", { style: {
520
559
  display: "flex",
521
560
  alignItems: "center",
@@ -0,0 +1,155 @@
1
+ "use client";
2
+ import React from "react";
3
+ // Loader/Spinner Icon Component
4
+ export const LoaderIcon = ({ size = 20, className = "", style = {}, }) => {
5
+ return (React.createElement(React.Fragment, null,
6
+ React.createElement("style", null, `
7
+ @keyframes icon-spin {
8
+ from { transform: rotate(0deg); }
9
+ to { transform: rotate(360deg); }
10
+ }
11
+ `),
12
+ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: `lucide lucide-loader-circle ${className}`, style: Object.assign({ animation: "icon-spin 1s linear infinite" }, style) },
13
+ React.createElement("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }))));
14
+ };
15
+ // Arrow Up Icon Component
16
+ export const ArrowUpIcon = ({ size = 20, className = "", style = {}, }) => {
17
+ return (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: `lucide lucide-arrow-up ${className}`, style: Object.assign({}, style) },
18
+ React.createElement("path", { d: "m5 12 7-7 7 7" }),
19
+ React.createElement("path", { d: "M12 19V5" })));
20
+ };
21
+ export const VoiceIcon = ({ isRecording = false, isTranscribing = false, size = 20, style = {}, }) => {
22
+ const containerStyle = Object.assign({ position: "relative", width: `${size}px`, height: `${Math.floor(size * 0.8)}px`, display: "flex", alignItems: "center", justifyContent: "center" }, style);
23
+ if (isTranscribing) {
24
+ return (React.createElement(React.Fragment, null,
25
+ React.createElement("style", null, `
26
+ @keyframes icon-spin {
27
+ from { transform: rotate(0deg); }
28
+ to { transform: rotate(360deg); }
29
+ }
30
+ `),
31
+ React.createElement("div", { style: containerStyle },
32
+ React.createElement("div", { style: {
33
+ width: `${Math.floor(size * 0.6)}px`,
34
+ height: `${Math.floor(size * 0.6)}px`,
35
+ border: "2px solid currentColor",
36
+ borderTop: "2px solid transparent",
37
+ borderRadius: "50%",
38
+ animation: "icon-spin 1s linear infinite",
39
+ } }))));
40
+ }
41
+ if (isRecording) {
42
+ return (React.createElement(React.Fragment, null,
43
+ React.createElement("style", null, `
44
+ @keyframes icon-pulse {
45
+ 0%, 100% { transform: scale(1); }
46
+ 50% { transform: scale(0.95); }
47
+ }
48
+ `),
49
+ React.createElement("div", { style: containerStyle },
50
+ React.createElement("div", { style: {
51
+ width: `${Math.floor(size * 0.6)}px`,
52
+ height: `${Math.floor(size * 0.6)}px`,
53
+ backgroundColor: "currentColor",
54
+ borderRadius: "2px",
55
+ animation: "icon-pulse 1s ease-in-out infinite",
56
+ } }))));
57
+ }
58
+ // Default voice icon with sound wave animation
59
+ const barWidth = Math.max(1, Math.floor(size * 0.075));
60
+ const gap = Math.max(1, Math.floor(size * 0.1));
61
+ return (React.createElement(React.Fragment, null,
62
+ React.createElement("style", null, `
63
+ @keyframes wave1 {
64
+ 0%, 100% {
65
+ transform: scaleY(0.4);
66
+ opacity: 0.6;
67
+ }
68
+ 50% {
69
+ transform: scaleY(0.8);
70
+ opacity: 0.9;
71
+ }
72
+ }
73
+
74
+ @keyframes wave2 {
75
+ 0%, 100% {
76
+ transform: scaleY(0.5);
77
+ opacity: 0.7;
78
+ }
79
+ 50% {
80
+ transform: scaleY(1);
81
+ opacity: 1;
82
+ }
83
+ }
84
+
85
+ @keyframes wave3 {
86
+ 0%, 100% {
87
+ transform: scaleY(0.6);
88
+ opacity: 0.8;
89
+ }
90
+ 50% {
91
+ transform: scaleY(1);
92
+ opacity: 1;
93
+ }
94
+ }
95
+
96
+ @keyframes wave4 {
97
+ 0%, 100% {
98
+ transform: scaleY(0.5);
99
+ opacity: 0.7;
100
+ }
101
+ 50% {
102
+ transform: scaleY(0.9);
103
+ opacity: 1;
104
+ }
105
+ }
106
+
107
+ @keyframes wave5 {
108
+ 0%, 100% {
109
+ transform: scaleY(0.4);
110
+ opacity: 0.6;
111
+ }
112
+ 50% {
113
+ transform: scaleY(0.7);
114
+ opacity: 0.9;
115
+ }
116
+ }
117
+ `),
118
+ React.createElement("div", { style: containerStyle },
119
+ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: `${gap}px` } },
120
+ React.createElement("div", { style: {
121
+ width: `${barWidth}px`,
122
+ height: `${Math.floor(size * 0.4)}px`,
123
+ backgroundColor: "currentColor",
124
+ borderRadius: "999px",
125
+ animation: "wave1 1.8s ease-in-out infinite",
126
+ } }),
127
+ React.createElement("div", { style: {
128
+ width: `${barWidth}px`,
129
+ height: `${Math.floor(size * 0.6)}px`,
130
+ backgroundColor: "currentColor",
131
+ borderRadius: "999px",
132
+ animation: "wave2 2.1s ease-in-out infinite",
133
+ } }),
134
+ React.createElement("div", { style: {
135
+ width: `${barWidth}px`,
136
+ height: `${Math.floor(size * 0.8)}px`,
137
+ backgroundColor: "currentColor",
138
+ borderRadius: "999px",
139
+ animation: "wave3 1.6s ease-in-out infinite",
140
+ } }),
141
+ React.createElement("div", { style: {
142
+ width: `${barWidth}px`,
143
+ height: `${Math.floor(size * 0.6)}px`,
144
+ backgroundColor: "currentColor",
145
+ borderRadius: "999px",
146
+ animation: "wave4 1.9s ease-in-out infinite",
147
+ } }),
148
+ React.createElement("div", { style: {
149
+ width: `${barWidth}px`,
150
+ height: `${Math.floor(size * 0.4)}px`,
151
+ backgroundColor: "currentColor",
152
+ borderRadius: "999px",
153
+ animation: "wave5 2.2s ease-in-out infinite",
154
+ } })))));
155
+ };
@@ -0,0 +1,51 @@
1
+ // src/components/MinimalChatBar.tsx
2
+ import React, { useState } from "react";
3
+ export const MinimalChatBar = ({ placeholder = "Ask anything...", onSubmit, theme = "light", }) => {
4
+ const [message, setMessage] = useState("");
5
+ const handleSubmit = (e) => {
6
+ e.preventDefault();
7
+ if (message.trim()) {
8
+ onSubmit === null || onSubmit === void 0 ? void 0 : onSubmit(message.trim());
9
+ setMessage("");
10
+ }
11
+ };
12
+ return (React.createElement("div", { style: {
13
+ width: "100%",
14
+ maxWidth: "600px",
15
+ margin: "0 auto",
16
+ } },
17
+ React.createElement("form", { onSubmit: handleSubmit, style: {
18
+ display: "flex",
19
+ gap: "8px",
20
+ padding: "12px",
21
+ border: theme === "dark" ? "1px solid #333" : "1px solid #ccc",
22
+ borderRadius: "8px",
23
+ backgroundColor: theme === "dark" ? "#1a1a1a" : "#ffffff",
24
+ boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
25
+ } },
26
+ React.createElement("input", { type: "text", value: message, onChange: (e) => setMessage(e.target.value), placeholder: placeholder, style: {
27
+ flex: 1,
28
+ padding: "8px 12px",
29
+ border: "1px solid #ddd",
30
+ borderRadius: "4px",
31
+ fontSize: "14px",
32
+ outline: "none",
33
+ backgroundColor: theme === "dark" ? "#333" : "#fff",
34
+ color: theme === "dark" ? "#fff" : "#000",
35
+ } }),
36
+ React.createElement("button", { type: "submit", disabled: !message.trim(), style: {
37
+ padding: "8px 16px",
38
+ backgroundColor: message.trim() ? "#007bff" : "#ccc",
39
+ color: "white",
40
+ border: "none",
41
+ borderRadius: "4px",
42
+ cursor: message.trim() ? "pointer" : "not-allowed",
43
+ fontSize: "14px",
44
+ } }, "Send")),
45
+ React.createElement("p", { style: {
46
+ fontSize: "12px",
47
+ color: "#666",
48
+ textAlign: "center",
49
+ marginTop: "8px",
50
+ } }, "SDK Version: @sampleapp.ai/sdk v1.0.25")));
51
+ };