goji-search 1.0.0 → 1.1.0

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.
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Sparkles } from "lucide-react";
3
3
  import { useEffect, useState } from "react";
4
4
  import { InspirationMenu } from "./inspiration-menu";
5
+ import AutoExpandingTextarea from "./auto-expanding-textarea"; // make sure path matches
5
6
  export function SearchInput({ value, onChange, onFocus, onBlur, placeholder, size, inputRef, inspirationQuestions, onInspirationClick, sparkleRef, }) {
6
7
  const [showInspirationMenu, setShowInspirationMenu] = useState(false);
7
8
  const [isSparkleHovered, setIsSparkleHovered] = useState(false);
@@ -9,37 +10,31 @@ export function SearchInput({ value, onChange, onFocus, onBlur, placeholder, siz
9
10
  const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0);
10
11
  const [isTyping, setIsTyping] = useState(true);
11
12
  const [charIndex, setCharIndex] = useState(0);
13
+ // Typewriter animation for placeholder
12
14
  useEffect(() => {
13
- if (size !== "s" || value || inspirationQuestions.length === 0) {
15
+ if (size !== "s" || value || inspirationQuestions.length === 0)
14
16
  return;
15
- }
16
17
  const currentQuestion = inspirationQuestions[currentQuestionIndex];
17
- const typingSpeed = 40; // ms per character when typing
18
- const deletingSpeed = 20; // ms per character when deleting
19
- const pauseAfterTyping = 2000; // pause when fully typed
20
- const pauseAfterDeleting = 500; // pause before typing next question
18
+ const typingSpeed = 40;
19
+ const deletingSpeed = 20;
20
+ const pauseAfterTyping = 2000;
21
+ const pauseAfterDeleting = 500;
21
22
  const timer = setTimeout(() => {
22
23
  if (isTyping) {
23
- // Typing phase
24
24
  if (charIndex < currentQuestion.length) {
25
25
  setTypewriterText(currentQuestion.slice(0, charIndex + 1));
26
26
  setCharIndex(charIndex + 1);
27
27
  }
28
28
  else {
29
- // Finished typing, pause then start deleting
30
- setTimeout(() => {
31
- setIsTyping(false);
32
- }, pauseAfterTyping);
29
+ setTimeout(() => setIsTyping(false), pauseAfterTyping);
33
30
  }
34
31
  }
35
32
  else {
36
- // Deleting phase
37
33
  if (charIndex > 0) {
38
34
  setTypewriterText(currentQuestion.slice(0, charIndex - 1));
39
35
  setCharIndex(charIndex - 1);
40
36
  }
41
37
  else {
42
- // Finished deleting, move to next question
43
38
  setTimeout(() => {
44
39
  setCurrentQuestionIndex((currentQuestionIndex + 1) % inspirationQuestions.length);
45
40
  setIsTyping(true);
@@ -57,34 +52,43 @@ export function SearchInput({ value, onChange, onFocus, onBlur, placeholder, siz
57
52
  setShowInspirationMenu(false);
58
53
  };
59
54
  const displayPlaceholder = size === "s" && !value ? typewriterText : placeholder;
60
- return (_jsxs("div", { style: { position: "relative" }, children: [_jsxs("div", { ref: sparkleRef, onClick: handleSparkleClick, onMouseEnter: () => setIsSparkleHovered(true), onMouseLeave: () => setIsSparkleHovered(false), style: {
55
+ return (_jsxs("div", { style: { position: "relative", zIndex: 1 }, children: [_jsxs("div", { ref: sparkleRef, onClick: handleSparkleClick, onMouseEnter: () => setIsSparkleHovered(true), onMouseLeave: () => setIsSparkleHovered(false), style: {
61
56
  position: "absolute",
62
57
  left: "0.75rem",
63
- top: "50%",
64
- transform: "translateY(-50%)",
58
+ top: "0.55rem",
65
59
  cursor: "pointer",
66
- zIndex: 10,
60
+ // Keep the trigger above the input; menu has an even higher z-index
61
+ zIndex: 2,
67
62
  }, children: [_jsx(Sparkles, { style: {
68
63
  width: size === "s" ? "0.875rem" : "1rem",
69
64
  height: size === "s" ? "0.875rem" : "1rem",
70
65
  color: "rgba(0, 0, 0, 0.6)",
71
66
  transition: "all 0.3s ease",
72
- } }), showInspirationMenu && (_jsx(InspirationMenu, { questions: inspirationQuestions, onQuestionClick: handleQuestionClick, onClose: () => setShowInspirationMenu(false) }))] }), _jsx("input", { ref: inputRef, type: "text", value: value, onChange: onChange, onFocus: onFocus, className: "sparkle-input", onBlur: onBlur, placeholder: displayPlaceholder, style: {
73
- width: "100%",
74
- borderRadius: "1.3rem",
75
- border: "1px solid rgba(255, 255, 255, 0.25)",
76
- backgroundColor: "rgba(255, 255, 255, 0.3)",
77
- padding: size === "s" ? "0.375rem 0.5rem 0.375rem 2rem" : "0.5rem 0.75rem 0.5rem 2.25rem",
78
- fontSize: size === "s" ? "0.8125rem" : "0.875rem",
79
- color: "rgba(0, 0, 0, 0.85)",
80
- backdropFilter: "blur(20px) saturate(180%)",
81
- WebkitBackdropFilter: "blur(20px) saturate(180%)",
82
- transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
67
+ } }), showInspirationMenu && (_jsx(InspirationMenu, { questions: inspirationQuestions, onQuestionClick: handleQuestionClick, onClose: () => setShowInspirationMenu(false) }))] }), _jsx(AutoExpandingTextarea, { ref: inputRef, value: value, onChange: onChange, onFocus: onFocus, onBlur: onBlur, placeholder: displayPlaceholder, className: `sparkle-input ${isSparkleHovered ? "sparkle-hover" : ""}`, style: {
68
+ padding: "0.2rem 0.75rem 0.2rem 2rem",
83
69
  outline: "none",
84
- boxShadow: "inset 0 1px 0 rgba(255, 255, 255, 0.4)",
70
+ transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
85
71
  } }), _jsx("style", { children: `
86
- input::placeholder {
87
- color: rgba(0, 0, 0, 0.75);
88
- }
89
- ` })] }));
72
+ .sparkle-input {
73
+ width: 100%;
74
+ border: 1px solid rgba(255, 255, 255, 0.25);
75
+ background-color: transparent;
76
+ border-radius: 9999px; /* full rounded */
77
+ font-size: 0.875rem; /* ~14px */
78
+ color: rgba(0, 0, 0, 0.85);
79
+ backdrop-filter: blur(20px) saturate(180%);
80
+ -webkit-backdrop-filter: blur(20px) saturate(180%);
81
+ resize: none;
82
+ outline: none;
83
+ overflow: hidden; /* hide scrollbar toggles */
84
+ line-height: 1.5rem;
85
+ min-height: 1.5rem;
86
+ max-height: 160px;
87
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
88
+ }
89
+
90
+ .sparkle-input::placeholder {
91
+ color: rgba(0, 0, 0, 0.75);
92
+ }
93
+ ` })] }));
90
94
  }
@@ -4,7 +4,7 @@ export function SuggestedQuestions({ questions, onQuestionClick }) {
4
4
  display: "flex",
5
5
  flexDirection: "column",
6
6
  gap: "0.5rem",
7
- padding: "0.625rem",
7
+ padding: "0 0.625rem",
8
8
  borderRadius: "0.75rem",
9
9
  backgroundColor: "rgba(255, 255, 255, 0.08)",
10
10
  border: "1px solid rgba(255, 255, 255, 0.15)",
@@ -1,2 +1,10 @@
1
1
  import "./goji-search.css";
2
- export declare function GojiSearchComponent(): import("react/jsx-runtime").JSX.Element;
2
+ export interface GojiSearchComponentProps {
3
+ /**
4
+ * Backend API URL for GojiSearch
5
+ * @default "http://localhost:8000"
6
+ * @example "https://api.example.com"
7
+ */
8
+ apiUrl?: string;
9
+ }
10
+ export declare function GojiSearchComponent({ apiUrl }?: GojiSearchComponentProps): import("react/jsx-runtime").JSX.Element;