@kaifusion/widget 1.0.5 → 1.0.7

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/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@kaifusion/widget",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "type": "module",
5
- "main": "./dist/index.es.js",
5
+ "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.es.js",
7
7
  "types": "./dist/index.d.ts",
8
8
  "files": [
@@ -13,7 +13,7 @@
13
13
  ".": {
14
14
  "types": "./dist/index.d.ts",
15
15
  "import": "./dist/index.es.js",
16
- "require": "./dist/index.es.js"
16
+ "require": "./dist/index.cjs"
17
17
  }
18
18
  },
19
19
  "scripts": {
@@ -24,6 +24,7 @@ import {
24
24
  } from "lucide-react";
25
25
  import { motion, AnimatePresence } from "motion/react";
26
26
  import { v4 as uuidv4 } from "uuid";
27
+ import { config } from "./config";
27
28
 
28
29
  interface Message {
29
30
  id: string;
@@ -67,12 +68,34 @@ export default function KaiChatWidget({
67
68
  const [userProvidedToken, setUserProvidedToken] = useState<string | null>(
68
69
  null
69
70
  );
71
+ const [isTokenValidating, setIsTokenValidating] = useState(false);
72
+ const [tokenError, setTokenError] = useState<string | null>(null);
73
+ const [isInputFocused, setIsInputFocused] = useState(false);
70
74
 
71
75
  const effectiveToken = authToken || userProvidedToken;
76
+ const handleTokenSubmit = async (token: string) => {
77
+ if (!token.trim() || isTokenValidating) return;
72
78
 
73
- const handleTokenSubmit = (token: string) => {
74
- if (token.trim()) {
75
- setUserProvidedToken(token);
79
+ setIsTokenValidating(true);
80
+ setTokenError(null);
81
+
82
+ try {
83
+ const response = await fetch(`${targetUrl}/${config.API_START}/${config.API_VERSION_ONLY}/auth/me`, {
84
+ headers: {
85
+ Authorization: `Bearer ${token}`,
86
+ },
87
+ });
88
+
89
+ if (response.ok) {
90
+ setUserProvidedToken(token);
91
+ } else {
92
+ setTokenError("Geçersiz Erişim Anahtarı. Lütfen tekrar deneyiniz.");
93
+ }
94
+ } catch (error) {
95
+ console.error("Token validation error:", error);
96
+ setTokenError("Bağlantı hatası. Lütfen tekrar deneyiniz.");
97
+ } finally {
98
+ setIsTokenValidating(false);
76
99
  }
77
100
  };
78
101
 
@@ -134,7 +157,7 @@ export default function KaiChatWidget({
134
157
  headers["X-API-Key"] = token;
135
158
  }
136
159
 
137
- const response = await fetch(`${targetUrl}/api/v1/workflows/execute`, {
160
+ const response = await fetch(`${targetUrl}/${config.API_START}/${config.API_VERSION_ONLY}/workflows/execute`, {
138
161
  method: "POST",
139
162
  headers,
140
163
  body: JSON.stringify({
@@ -229,9 +252,8 @@ export default function KaiChatWidget({
229
252
 
230
253
  return (
231
254
  <div
232
- className={`fixed bottom-5 z-50 flex flex-col items-end gap-4 font-sans ${
233
- position === "left" ? "left-5" : "right-5"
234
- }`}
255
+ className={`fixed bottom-5 z-50 flex flex-col items-end gap-4 font-sans ${position === "left" ? "left-5" : "right-5"
256
+ }`}
235
257
  style={{ fontFamily: "system-ui, -apple-system, sans-serif" }}
236
258
  >
237
259
  {/* Overlay - Tam Ekran Modu İçin */}
@@ -260,11 +282,10 @@ export default function KaiChatWidget({
260
282
  height: isMaximized ? "85vh" : "600px",
261
283
  }}
262
284
  exit={{ opacity: 0, y: 20, scale: 0.95 }}
263
- className={`rounded-2xl shadow-2xl flex flex-col overflow-hidden z-50 transition-all duration-300 ${
264
- isMaximized
265
- ? "fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 m-0"
266
- : "relative"
267
- }`}
285
+ className={`rounded-2xl shadow-2xl flex flex-col overflow-hidden z-50 transition-all duration-300 ${isMaximized
286
+ ? "fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 m-0"
287
+ : "relative"
288
+ }`}
268
289
  >
269
290
  {/* Header */}
270
291
  <div
@@ -301,20 +322,17 @@ export default function KaiChatWidget({
301
322
  {messages.map((msg) => (
302
323
  <div
303
324
  key={msg.id}
304
- className={`flex ${
305
- msg.isBot ? "justify-start" : "justify-end"
306
- } ${
307
- msg.isBot && !msg.content && !msg.isError ? "hidden" : ""
308
- }`}
325
+ className={`flex ${msg.isBot ? "justify-start" : "justify-end"
326
+ } ${msg.isBot && !msg.content && !msg.isError ? "hidden" : ""
327
+ }`}
309
328
  >
310
329
  <div
311
- className={`max-w-[85%] rounded-2xl px-4 py-3 shadow-sm ${
312
- msg.isBot
313
- ? msg.isError
314
- ? "bg-red-50 text-red-600 border border-red-100"
315
- : "bg-white text-gray-800 border border-gray-100"
316
- : "text-white"
317
- }`}
330
+ className={`max-w-[85%] rounded-2xl px-4 py-3 shadow-sm ${msg.isBot
331
+ ? msg.isError
332
+ ? "bg-red-50 text-red-600 border border-red-100"
333
+ : "bg-white text-gray-800 border border-gray-100"
334
+ : "text-white"
335
+ }`}
318
336
  style={!msg.isBot ? { backgroundColor: color } : {}}
319
337
  >
320
338
  <div className="max-w-none break-words">
@@ -461,9 +479,8 @@ export default function KaiChatWidget({
461
479
 
462
480
  return isOrderedList ? (
463
481
  <li
464
- className={`flex items-start gap-2 pl-1 leading-relaxed ${
465
- !msg.isBot ? "text-white" : "text-gray-700"
466
- }`}
482
+ className={`flex items-start gap-2 pl-1 leading-relaxed ${!msg.isBot ? "text-white" : "text-gray-700"
483
+ }`}
467
484
  >
468
485
  <span className="flex-shrink-0 w-5 h-5 bg-gradient-to-r from-blue-500 to-purple-600 text-white rounded-full flex items-center justify-center text-[10px] font-bold mt-0.5 shadow-sm counter-increment">
469
486
 
@@ -474,9 +491,8 @@ export default function KaiChatWidget({
474
491
  </li>
475
492
  ) : (
476
493
  <li
477
- className={`flex items-start gap-2 pl-1 leading-relaxed ${
478
- !msg.isBot ? "text-white" : "text-gray-700"
479
- }`}
494
+ className={`flex items-start gap-2 pl-1 leading-relaxed ${!msg.isBot ? "text-white" : "text-gray-700"
495
+ }`}
480
496
  >
481
497
  <span className="flex-shrink-0 w-1.5 h-1.5 bg-gradient-to-r from-blue-500 to-purple-600 rounded-full mt-2 shadow-sm"></span>
482
498
  <div className="flex-1 text-left">
@@ -566,9 +582,8 @@ export default function KaiChatWidget({
566
582
  // Paragraflar - daha iyi spacing
567
583
  p: ({ children }: any) => (
568
584
  <p
569
- className={`m-0! last:mb-0 leading-relaxed break-words overflow-wrap-anywhere text-sm ${
570
- !msg.isBot ? "text-white" : "text-gray-700"
571
- }`}
585
+ className={`m-0! last:mb-0 leading-relaxed break-words overflow-wrap-anywhere text-sm ${!msg.isBot ? "text-white" : "text-gray-700"
586
+ }`}
572
587
  >
573
588
  {children}
574
589
  </p>
@@ -577,18 +592,16 @@ export default function KaiChatWidget({
577
592
  // Vurgu metinleri
578
593
  strong: ({ children }: any) => (
579
594
  <strong
580
- className={`font-bold inline ${
581
- !msg.isBot ? "text-white" : "text-gray-900"
582
- }`}
595
+ className={`font-bold inline ${!msg.isBot ? "text-white" : "text-gray-900"
596
+ }`}
583
597
  >
584
598
  {children}
585
599
  </strong>
586
600
  ),
587
601
  em: ({ children }: any) => (
588
602
  <em
589
- className={`italic ${
590
- !msg.isBot ? "text-white/90" : "text-gray-600"
591
- }`}
603
+ className={`italic ${!msg.isBot ? "text-white/90" : "text-gray-600"
604
+ }`}
592
605
  >
593
606
  {children}
594
607
  </em>
@@ -668,12 +681,20 @@ export default function KaiChatWidget({
668
681
  {/* Input Alanı */}
669
682
  {effectiveToken ? (
670
683
  <div className="p-4 bg-white border-t border-gray-100">
671
- <div className="flex gap-2 items-center bg-gray-50 rounded-full px-4 py-2 border border-gray-200 focus-within:border-blue-500 focus-within:ring-1 focus-within:ring-blue-500 transition-all">
684
+ <div
685
+ className="flex gap-2 items-center bg-gray-50 rounded-full px-4 py-2 border border-gray-200 transition-all"
686
+ style={{
687
+ borderColor: isInputFocused ? color : undefined,
688
+ boxShadow: isInputFocused ? `0 0 0 1px ${color}` : undefined,
689
+ }}
690
+ >
672
691
  <input
673
692
  type="text"
674
693
  value={input}
675
694
  onChange={(e) => setInput(e.target.value)}
676
695
  onKeyDown={(e) => e.key === "Enter" && sendMessage()}
696
+ onFocus={() => setIsInputFocused(true)}
697
+ onBlur={() => setIsInputFocused(false)}
677
698
  placeholder="Mesajınızı yazın..."
678
699
  className="flex-1 bg-transparent border-none focus:ring-0 outline-none text-sm py-1 text-black"
679
700
  disabled={isLoading}
@@ -681,11 +702,13 @@ export default function KaiChatWidget({
681
702
  <button
682
703
  onClick={sendMessage}
683
704
  disabled={isLoading || !input.trim()}
684
- className={`p-2 rounded-full transition-all ${
685
- input.trim() && !isLoading
686
- ? "text-blue-600 hover:bg-blue-50"
687
- : "text-gray-400"
688
- }`}
705
+ className={`p-2 rounded-full transition-all ${input.trim() && !isLoading
706
+ ? "hover:bg-gray-100"
707
+ : "text-gray-400"
708
+ }`}
709
+ style={{
710
+ color: input.trim() && !isLoading ? color : undefined,
711
+ }}
689
712
  >
690
713
  {isLoading ? (
691
714
  <Loader2 className="w-5 h-5 animate-spin" />
@@ -710,7 +733,9 @@ export default function KaiChatWidget({
710
733
  <input
711
734
  type="password"
712
735
  placeholder="Access Token"
713
- className="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 outline-none text-sm text-gray-800"
736
+ className={`flex-1 px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500 outline-none text-sm text-gray-800 ${tokenError ? "border-red-500" : "border-gray-300"
737
+ }`}
738
+ disabled={isTokenValidating}
714
739
  onKeyDown={(e) => {
715
740
  if (e.key === "Enter") {
716
741
  handleTokenSubmit(e.currentTarget.value);
@@ -718,16 +743,26 @@ export default function KaiChatWidget({
718
743
  }}
719
744
  />
720
745
  <button
721
- className="bg-blue-600 hover:bg-blue-700 text-white font-medium px-4 rounded-lg transition-colors text-sm"
746
+ className="bg-blue-600 hover:bg-blue-700 text-white font-medium px-4 rounded-lg transition-colors text-sm disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center min-w-[60px]"
747
+ disabled={isTokenValidating}
722
748
  onClick={(e) => {
723
749
  const inputEl = e.currentTarget
724
750
  .previousElementSibling as HTMLInputElement;
725
751
  handleTokenSubmit(inputEl.value);
726
752
  }}
727
753
  >
728
- Giriş
754
+ {isTokenValidating ? (
755
+ <Loader2 className="w-4 h-4 animate-spin" />
756
+ ) : (
757
+ "Giriş"
758
+ )}
729
759
  </button>
730
760
  </div>
761
+ {tokenError && (
762
+ <p className="text-xs text-red-500 text-center">
763
+ {tokenError}
764
+ </p>
765
+ )}
731
766
  </div>
732
767
  </div>
733
768
  )}
package/src/config.ts ADDED
@@ -0,0 +1,27 @@
1
+ // Widget-specific configuration
2
+ // This is a standalone config for the widget package to avoid
3
+ // dependencies on the client package during Docker builds
4
+
5
+ export interface WidgetConfig {
6
+ API_START: string;
7
+ API_VERSION_ONLY: string;
8
+ }
9
+
10
+ // Default values that can be overridden via props or window globals
11
+ const getWidgetConfig = (): WidgetConfig => {
12
+ // Check for window globals (for runtime configuration)
13
+ if (typeof window !== 'undefined') {
14
+ return {
15
+ API_START: (window as any).VITE_API_START || 'api',
16
+ API_VERSION_ONLY: (window as any).VITE_API_VERSION_ONLY || 'v1',
17
+ };
18
+ }
19
+
20
+ // Fallback defaults
21
+ return {
22
+ API_START: 'api',
23
+ API_VERSION_ONLY: 'v1',
24
+ };
25
+ };
26
+
27
+ export const config = getWidgetConfig();