@kaifusion/widget 1.0.4 → 1.0.6
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/README.md +49 -0
- package/dist/widget.iife.js +452 -0
- package/package.json +10 -1
- package/src/KaiChatWidget.tsx +113 -34
- package/src/embed.tsx +94 -0
- package/src/index.css +2 -0
- package/dist/KaiChatWidget.d.ts +0 -10
- package/dist/index.d.ts +0 -2
- package/dist/index.es.js +0 -66505
- package/dist/index.es.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kaifusion/widget",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.es.js",
|
|
6
6
|
"module": "./dist/index.es.js",
|
|
@@ -19,8 +19,13 @@
|
|
|
19
19
|
"scripts": {
|
|
20
20
|
"dev": "vite",
|
|
21
21
|
"build": "tsc && vite build",
|
|
22
|
+
"build:standalone": "vite build --config vite.config.standalone.ts",
|
|
22
23
|
"preview": "vite preview"
|
|
23
24
|
},
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
27
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
28
|
+
},
|
|
24
29
|
"dependencies": {
|
|
25
30
|
"lucide-react": "^0.524.0",
|
|
26
31
|
"motion": "^12.23.12",
|
|
@@ -30,14 +35,18 @@
|
|
|
30
35
|
"rehype-raw": "^7.0.0",
|
|
31
36
|
"remark-gfm": "^4.0.1",
|
|
32
37
|
"remark-math": "^6.0.0",
|
|
38
|
+
"rollup": "^4.54.0",
|
|
33
39
|
"uuid": "^11.1.0"
|
|
34
40
|
},
|
|
35
41
|
"devDependencies": {
|
|
42
|
+
"@tailwindcss/vite": "^4.1.4",
|
|
36
43
|
"@types/node": "^25.0.3",
|
|
37
44
|
"@types/react": "^19.1.8",
|
|
38
45
|
"@types/react-dom": "^19.1.6",
|
|
39
46
|
"@types/react-syntax-highlighter": "^15.5.13",
|
|
40
47
|
"@vitejs/plugin-react": "^4.2.0",
|
|
48
|
+
"react": "^19.0.0",
|
|
49
|
+
"react-dom": "^19.0.0",
|
|
41
50
|
"tailwindcss": "^4.1.4",
|
|
42
51
|
"typescript": "^5.8.3",
|
|
43
52
|
"vite": "^6.3.3",
|
package/src/KaiChatWidget.tsx
CHANGED
|
@@ -34,7 +34,7 @@ interface Message {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
export interface KaiChatWidgetProps {
|
|
37
|
-
authToken
|
|
37
|
+
authToken?: string;
|
|
38
38
|
workflowId: string;
|
|
39
39
|
title?: string;
|
|
40
40
|
targetUrl: string;
|
|
@@ -64,6 +64,40 @@ export default function KaiChatWidget({
|
|
|
64
64
|
]);
|
|
65
65
|
const [input, setInput] = useState("");
|
|
66
66
|
const [isLoading, setIsLoading] = useState(false);
|
|
67
|
+
const [userProvidedToken, setUserProvidedToken] = useState<string | null>(
|
|
68
|
+
null
|
|
69
|
+
);
|
|
70
|
+
const [isTokenValidating, setIsTokenValidating] = useState(false);
|
|
71
|
+
const [tokenError, setTokenError] = useState<string | null>(null);
|
|
72
|
+
|
|
73
|
+
const effectiveToken = authToken || userProvidedToken;
|
|
74
|
+
|
|
75
|
+
const handleTokenSubmit = async (token: string) => {
|
|
76
|
+
if (!token.trim() || isTokenValidating) return;
|
|
77
|
+
|
|
78
|
+
setIsTokenValidating(true);
|
|
79
|
+
setTokenError(null);
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
const response = await fetch(`${targetUrl}/api/v1/auth/me`, {
|
|
83
|
+
headers: {
|
|
84
|
+
Authorization: `Bearer ${token}`,
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
if (response.ok) {
|
|
89
|
+
setUserProvidedToken(token);
|
|
90
|
+
} else {
|
|
91
|
+
setTokenError("Geçersiz Erişim Anahtarı. Lütfen tekrar deneyiniz.");
|
|
92
|
+
}
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error("Token validation error:", error);
|
|
95
|
+
setTokenError("Bağlantı hatası. Lütfen tekrar deneyiniz.");
|
|
96
|
+
} finally {
|
|
97
|
+
setIsTokenValidating(false);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
67
101
|
const [copiedCode, setCopiedCode] = useState<string | null>(null);
|
|
68
102
|
const messagesEndRef = useRef<HTMLDivElement>(null);
|
|
69
103
|
const sessionIdRef = useRef(uuidv4());
|
|
@@ -111,7 +145,7 @@ export default function KaiChatWidget({
|
|
|
111
145
|
]);
|
|
112
146
|
|
|
113
147
|
try {
|
|
114
|
-
const token =
|
|
148
|
+
const token = effectiveToken;
|
|
115
149
|
const headers: Record<string, string> = {
|
|
116
150
|
"Content-Type": "application/json",
|
|
117
151
|
Accept: "text/event-stream",
|
|
@@ -654,39 +688,84 @@ export default function KaiChatWidget({
|
|
|
654
688
|
</div>
|
|
655
689
|
|
|
656
690
|
{/* Input Alanı */}
|
|
657
|
-
|
|
658
|
-
<div className="
|
|
659
|
-
<
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
691
|
+
{effectiveToken ? (
|
|
692
|
+
<div className="p-4 bg-white border-t border-gray-100">
|
|
693
|
+
<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">
|
|
694
|
+
<input
|
|
695
|
+
type="text"
|
|
696
|
+
value={input}
|
|
697
|
+
onChange={(e) => setInput(e.target.value)}
|
|
698
|
+
onKeyDown={(e) => e.key === "Enter" && sendMessage()}
|
|
699
|
+
placeholder="Mesajınızı yazın..."
|
|
700
|
+
className="flex-1 bg-transparent border-none focus:ring-0 outline-none text-sm py-1 text-black"
|
|
701
|
+
disabled={isLoading}
|
|
702
|
+
/>
|
|
703
|
+
<button
|
|
704
|
+
onClick={sendMessage}
|
|
705
|
+
disabled={isLoading || !input.trim()}
|
|
706
|
+
className={`p-2 rounded-full transition-all ${
|
|
707
|
+
input.trim() && !isLoading
|
|
708
|
+
? "text-blue-600 hover:bg-blue-50"
|
|
709
|
+
: "text-gray-400"
|
|
710
|
+
}`}
|
|
711
|
+
>
|
|
712
|
+
{isLoading ? (
|
|
713
|
+
<Loader2 className="w-5 h-5 animate-spin" />
|
|
714
|
+
) : (
|
|
715
|
+
<Send className="w-5 h-5" />
|
|
716
|
+
)}
|
|
717
|
+
</button>
|
|
718
|
+
</div>
|
|
719
|
+
<div className="text-center mt-2">
|
|
720
|
+
<span className="text-[10px] text-gray-400">
|
|
721
|
+
Powered by Agenticgro
|
|
722
|
+
</span>
|
|
723
|
+
</div>
|
|
683
724
|
</div>
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
725
|
+
) : (
|
|
726
|
+
<div className="p-4 bg-white border-t border-gray-100">
|
|
727
|
+
<div className="flex flex-col gap-3">
|
|
728
|
+
<p className="text-sm text-gray-600 text-center">
|
|
729
|
+
Devam etmek için lütfen Erişim Anahtarı giriniz:
|
|
730
|
+
</p>
|
|
731
|
+
<div className="flex gap-2">
|
|
732
|
+
<input
|
|
733
|
+
type="password"
|
|
734
|
+
placeholder="Access Token"
|
|
735
|
+
className={`flex-1 px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500 outline-none text-sm text-gray-800 ${
|
|
736
|
+
tokenError ? "border-red-500" : "border-gray-300"
|
|
737
|
+
}`}
|
|
738
|
+
disabled={isTokenValidating}
|
|
739
|
+
onKeyDown={(e) => {
|
|
740
|
+
if (e.key === "Enter") {
|
|
741
|
+
handleTokenSubmit(e.currentTarget.value);
|
|
742
|
+
}
|
|
743
|
+
}}
|
|
744
|
+
/>
|
|
745
|
+
<button
|
|
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}
|
|
748
|
+
onClick={(e) => {
|
|
749
|
+
const inputEl = e.currentTarget
|
|
750
|
+
.previousElementSibling as HTMLInputElement;
|
|
751
|
+
handleTokenSubmit(inputEl.value);
|
|
752
|
+
}}
|
|
753
|
+
>
|
|
754
|
+
{isTokenValidating ? (
|
|
755
|
+
<Loader2 className="w-4 h-4 animate-spin" />
|
|
756
|
+
) : (
|
|
757
|
+
"Giriş"
|
|
758
|
+
)}
|
|
759
|
+
</button>
|
|
760
|
+
</div>
|
|
761
|
+
{tokenError && (
|
|
762
|
+
<p className="text-xs text-red-500 text-center">
|
|
763
|
+
{tokenError}
|
|
764
|
+
</p>
|
|
765
|
+
)}
|
|
766
|
+
</div>
|
|
688
767
|
</div>
|
|
689
|
-
|
|
768
|
+
)}
|
|
690
769
|
</motion.div>
|
|
691
770
|
)}
|
|
692
771
|
</AnimatePresence>
|
|
@@ -708,4 +787,4 @@ export default function KaiChatWidget({
|
|
|
708
787
|
</motion.button>
|
|
709
788
|
</div>
|
|
710
789
|
);
|
|
711
|
-
}
|
|
790
|
+
}
|
package/src/embed.tsx
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import ReactDOM from "react-dom/client";
|
|
3
|
+
import KaiChatWidget, { KaiChatWidgetProps } from "./KaiChatWidget";
|
|
4
|
+
// @ts-ignore
|
|
5
|
+
import styles from "./index.css?inline";
|
|
6
|
+
|
|
7
|
+
declare global {
|
|
8
|
+
interface Window {
|
|
9
|
+
KaiChat: {
|
|
10
|
+
init: (config: KaiChatWidgetProps) => void;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const KAI_CHAT_HOST_ID = "kai-chat-widget-host";
|
|
16
|
+
|
|
17
|
+
function init(config: KaiChatWidgetProps) {
|
|
18
|
+
if (document.getElementById(KAI_CHAT_HOST_ID)) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const host = document.createElement("div");
|
|
23
|
+
host.id = KAI_CHAT_HOST_ID;
|
|
24
|
+
|
|
25
|
+
host.style.position = "fixed";
|
|
26
|
+
host.style.zIndex = "2147483647";
|
|
27
|
+
host.style.bottom = "0";
|
|
28
|
+
host.style.right = "0";
|
|
29
|
+
host.style.width = "0";
|
|
30
|
+
host.style.height = "0";
|
|
31
|
+
host.style.overflow = "visible";
|
|
32
|
+
|
|
33
|
+
document.body.appendChild(host);
|
|
34
|
+
|
|
35
|
+
const shadow = host.attachShadow({ mode: "open" });
|
|
36
|
+
|
|
37
|
+
const styleTag = document.createElement("style");
|
|
38
|
+
styleTag.textContent = styles;
|
|
39
|
+
shadow.appendChild(styleTag);
|
|
40
|
+
|
|
41
|
+
const mountPoint = document.createElement("div");
|
|
42
|
+
mountPoint.id = "kai-chat-root";
|
|
43
|
+
shadow.appendChild(mountPoint);
|
|
44
|
+
|
|
45
|
+
const root = ReactDOM.createRoot(mountPoint);
|
|
46
|
+
root.render(
|
|
47
|
+
<React.StrictMode>
|
|
48
|
+
<KaiChatWidget {...config} />
|
|
49
|
+
</React.StrictMode>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Global scope'a bağla
|
|
54
|
+
window.KaiChat = { init };
|
|
55
|
+
|
|
56
|
+
// OTOMATİK BAŞLATMA MANTIĞI
|
|
57
|
+
// Mevcut çalışan scripti bul (genellikle son eklenen scripttir veya src ile aranabilir)
|
|
58
|
+
// document.currentScript modern tarayıcılarda çalışır.
|
|
59
|
+
const currentScript = document.currentScript as HTMLScriptElement;
|
|
60
|
+
|
|
61
|
+
if (currentScript) {
|
|
62
|
+
const title = currentScript.getAttribute("data-title");
|
|
63
|
+
const authToken = currentScript.getAttribute("data-auth-token");
|
|
64
|
+
const workflowId = currentScript.getAttribute("data-workflow-id");
|
|
65
|
+
const targetUrl = currentScript.getAttribute("data-target-url");
|
|
66
|
+
const position = currentScript.getAttribute("data-position") as "left" | "right" | null;
|
|
67
|
+
const color = currentScript.getAttribute("data-color");
|
|
68
|
+
|
|
69
|
+
// Eğer gerekli parametreler varsa otomatik başlat
|
|
70
|
+
if (workflowId && targetUrl) {
|
|
71
|
+
// DOM hazır olana kadar bekle
|
|
72
|
+
if (document.readyState === "loading") {
|
|
73
|
+
document.addEventListener("DOMContentLoaded", () => {
|
|
74
|
+
init({
|
|
75
|
+
title: title || "ChatBot",
|
|
76
|
+
authToken: authToken || "",
|
|
77
|
+
workflowId,
|
|
78
|
+
targetUrl,
|
|
79
|
+
position: position || "right",
|
|
80
|
+
color: color || "#526cfe",
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
} else {
|
|
84
|
+
init({
|
|
85
|
+
title: title || "ChatBot",
|
|
86
|
+
authToken: authToken || "",
|
|
87
|
+
workflowId,
|
|
88
|
+
targetUrl,
|
|
89
|
+
position: position || "right",
|
|
90
|
+
color: color || "#526cfe",
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
package/src/index.css
ADDED
package/dist/KaiChatWidget.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export interface KaiChatWidgetProps {
|
|
2
|
-
authToken: string;
|
|
3
|
-
workflowId: string;
|
|
4
|
-
title?: string;
|
|
5
|
-
targetUrl: string;
|
|
6
|
-
position?: "left" | "right";
|
|
7
|
-
color?: string;
|
|
8
|
-
icon?: React.ReactNode;
|
|
9
|
-
}
|
|
10
|
-
export default function KaiChatWidget({ authToken, workflowId, title, targetUrl, position, color, icon, }: KaiChatWidgetProps): import("react/jsx-runtime").JSX.Element;
|
package/dist/index.d.ts
DELETED