@hookraft/use-claude-support 0.1.3
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/dist/index.cjs +483 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +28 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +456 -0
- package/dist/index.js.map +1 -0
- package/package.json +57 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
useClaudeSupport: () => useClaudeSupport
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(index_exports);
|
|
26
|
+
|
|
27
|
+
// src/SupportWidget.tsx
|
|
28
|
+
var import_react = require("react");
|
|
29
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
30
|
+
var CLAUDE_LOGO = "data:image/svg+xml;base64," + btoa(
|
|
31
|
+
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" fill="none">
|
|
32
|
+
<rect width="48" height="48" rx="12" fill="#D97757"/>
|
|
33
|
+
<path d="M32.16 13H28.7l-7.4 21.82h3.22l1.68-5.18h7.56l1.68 5.18h3.32L32.16 13zm-5.06 13.94 2.96-9.12 2.96 9.12h-5.92zM18.3 13h-3.46L11 22.06 7.16 13H3.7l5.96 13.44L3.7 39h3.46l4.62-10.5L16.4 39h3.46l-6-12.56L18.3 13z" fill="white"/>
|
|
34
|
+
</svg>`
|
|
35
|
+
);
|
|
36
|
+
function ChatIcon({ size = 24 }) {
|
|
37
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 2C6.477 2 2 6.477 2 12c0 1.89.525 3.66 1.438 5.168L2.546 21.16a.5.5 0 00.628.628l3.992-.892A9.96 9.96 0 0012 22c5.523 0 10-4.477 10-10S17.523 2 12 2z" }) });
|
|
38
|
+
}
|
|
39
|
+
function CloseIcon({ size = 18 }) {
|
|
40
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
41
|
+
"svg",
|
|
42
|
+
{
|
|
43
|
+
width: size,
|
|
44
|
+
height: size,
|
|
45
|
+
viewBox: "0 0 24 24",
|
|
46
|
+
fill: "none",
|
|
47
|
+
stroke: "currentColor",
|
|
48
|
+
strokeWidth: 2,
|
|
49
|
+
strokeLinecap: "round",
|
|
50
|
+
children: [
|
|
51
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
52
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
function SendIcon({ size = 18 }) {
|
|
58
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
59
|
+
"svg",
|
|
60
|
+
{
|
|
61
|
+
width: size,
|
|
62
|
+
height: size,
|
|
63
|
+
viewBox: "0 0 24 24",
|
|
64
|
+
fill: "none",
|
|
65
|
+
stroke: "currentColor",
|
|
66
|
+
strokeWidth: 2,
|
|
67
|
+
strokeLinecap: "round",
|
|
68
|
+
strokeLinejoin: "round",
|
|
69
|
+
children: [
|
|
70
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "22", y1: "2", x2: "11", y2: "13" }),
|
|
71
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
function TypingIndicator({ bg }) {
|
|
77
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
78
|
+
"div",
|
|
79
|
+
{
|
|
80
|
+
style: {
|
|
81
|
+
display: "flex",
|
|
82
|
+
gap: 4,
|
|
83
|
+
padding: "10px 14px",
|
|
84
|
+
background: bg,
|
|
85
|
+
borderRadius: "18px 18px 18px 4px",
|
|
86
|
+
width: "fit-content",
|
|
87
|
+
alignItems: "center"
|
|
88
|
+
},
|
|
89
|
+
children: [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
90
|
+
"span",
|
|
91
|
+
{
|
|
92
|
+
style: {
|
|
93
|
+
width: 7,
|
|
94
|
+
height: 7,
|
|
95
|
+
borderRadius: "50%",
|
|
96
|
+
background: "#9ca3af",
|
|
97
|
+
display: "inline-block",
|
|
98
|
+
animation: "bounce 1.2s infinite",
|
|
99
|
+
animationDelay: `${i * 0.2}s`
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
i
|
|
103
|
+
))
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
function useResolvedTheme(theme) {
|
|
108
|
+
const [resolved, setResolved] = (0, import_react.useState)("light");
|
|
109
|
+
(0, import_react.useEffect)(() => {
|
|
110
|
+
if (theme === "light" || theme === "dark") {
|
|
111
|
+
setResolved(theme);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const checkTheme = () => {
|
|
115
|
+
const html = document.documentElement;
|
|
116
|
+
const dataTheme = html.getAttribute("data-theme");
|
|
117
|
+
const classList = html.classList;
|
|
118
|
+
if (dataTheme === "dark" || classList.contains("dark")) {
|
|
119
|
+
setResolved("dark");
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (dataTheme === "light" || classList.contains("light")) {
|
|
123
|
+
setResolved("light");
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
127
|
+
setResolved(prefersDark ? "dark" : "light");
|
|
128
|
+
};
|
|
129
|
+
checkTheme();
|
|
130
|
+
const observer = new MutationObserver(checkTheme);
|
|
131
|
+
observer.observe(document.documentElement, {
|
|
132
|
+
attributes: true,
|
|
133
|
+
attributeFilter: ["class", "data-theme", "style"]
|
|
134
|
+
});
|
|
135
|
+
const mq = window.matchMedia("(prefers-color-scheme: dark)");
|
|
136
|
+
mq.addEventListener("change", checkTheme);
|
|
137
|
+
return () => {
|
|
138
|
+
observer.disconnect();
|
|
139
|
+
mq.removeEventListener("change", checkTheme);
|
|
140
|
+
};
|
|
141
|
+
}, [theme]);
|
|
142
|
+
return resolved;
|
|
143
|
+
}
|
|
144
|
+
function SupportWidgetComponent({
|
|
145
|
+
endpoint,
|
|
146
|
+
knowledge,
|
|
147
|
+
branding
|
|
148
|
+
}) {
|
|
149
|
+
const {
|
|
150
|
+
theme = "system",
|
|
151
|
+
primaryColor = "#D97757",
|
|
152
|
+
logo = CLAUDE_LOGO,
|
|
153
|
+
title = "Claude Support"
|
|
154
|
+
} = branding;
|
|
155
|
+
const resolvedTheme = useResolvedTheme(theme);
|
|
156
|
+
const isDark = resolvedTheme === "dark";
|
|
157
|
+
const colors = {
|
|
158
|
+
bg: isDark ? "#1a1a1a" : "#ffffff",
|
|
159
|
+
border: isDark ? "#333333" : "#e5e7eb",
|
|
160
|
+
text: isDark ? "#f1f1f1" : "#111111",
|
|
161
|
+
textMuted: isDark ? "#9ca3af" : "#6b7280",
|
|
162
|
+
inputBg: isDark ? "#2a2a2a" : "#ffffff",
|
|
163
|
+
assistantBubble: isDark ? "#2a2a2a" : "#f3f4f6",
|
|
164
|
+
assistantText: isDark ? "#f1f1f1" : "#111111"
|
|
165
|
+
};
|
|
166
|
+
const [open, setOpen] = (0, import_react.useState)(false);
|
|
167
|
+
const [messages, setMessages] = (0, import_react.useState)([]);
|
|
168
|
+
const [input, setInput] = (0, import_react.useState)("");
|
|
169
|
+
const [isTyping, setIsTyping] = (0, import_react.useState)(false);
|
|
170
|
+
const [error, setError] = (0, import_react.useState)(null);
|
|
171
|
+
const messagesEndRef = (0, import_react.useRef)(null);
|
|
172
|
+
const inputRef = (0, import_react.useRef)(null);
|
|
173
|
+
(0, import_react.useEffect)(() => {
|
|
174
|
+
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
175
|
+
}, [messages, isTyping]);
|
|
176
|
+
(0, import_react.useEffect)(() => {
|
|
177
|
+
if (open) setTimeout(() => inputRef.current?.focus(), 100);
|
|
178
|
+
}, [open]);
|
|
179
|
+
(0, import_react.useEffect)(() => {
|
|
180
|
+
const handler = (e) => {
|
|
181
|
+
if (e.key === "Escape") setOpen(false);
|
|
182
|
+
};
|
|
183
|
+
document.addEventListener("keydown", handler);
|
|
184
|
+
return () => document.removeEventListener("keydown", handler);
|
|
185
|
+
}, []);
|
|
186
|
+
const sendMessage = (0, import_react.useCallback)(async () => {
|
|
187
|
+
if (!input.trim() || isTyping) return;
|
|
188
|
+
setError(null);
|
|
189
|
+
const userMessage = {
|
|
190
|
+
id: crypto.randomUUID(),
|
|
191
|
+
role: "user",
|
|
192
|
+
content: input.trim(),
|
|
193
|
+
timestamp: Date.now()
|
|
194
|
+
};
|
|
195
|
+
const history = messages.map((m) => ({ role: m.role, content: m.content }));
|
|
196
|
+
setMessages((prev) => [...prev, userMessage]);
|
|
197
|
+
setInput("");
|
|
198
|
+
setIsTyping(true);
|
|
199
|
+
try {
|
|
200
|
+
const res = await fetch(endpoint, {
|
|
201
|
+
method: "POST",
|
|
202
|
+
headers: { "Content-Type": "application/json" },
|
|
203
|
+
body: JSON.stringify({ message: userMessage.content, history, knowledge })
|
|
204
|
+
});
|
|
205
|
+
if (!res.ok) throw new Error(`Request failed: ${res.status}`);
|
|
206
|
+
const data = await res.json();
|
|
207
|
+
const assistantMessage = {
|
|
208
|
+
id: crypto.randomUUID(),
|
|
209
|
+
role: "assistant",
|
|
210
|
+
content: data.reply,
|
|
211
|
+
timestamp: Date.now()
|
|
212
|
+
};
|
|
213
|
+
setMessages((prev) => [...prev, assistantMessage]);
|
|
214
|
+
} catch {
|
|
215
|
+
setError("Something went wrong. Please try again.");
|
|
216
|
+
} finally {
|
|
217
|
+
setIsTyping(false);
|
|
218
|
+
}
|
|
219
|
+
}, [input, isTyping, messages, endpoint, knowledge]);
|
|
220
|
+
const handleKeyDown = (e) => {
|
|
221
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
222
|
+
e.preventDefault();
|
|
223
|
+
sendMessage();
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
227
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: `
|
|
228
|
+
@keyframes bounce {
|
|
229
|
+
0%, 60%, 100% { transform: translateY(0); }
|
|
230
|
+
30% { transform: translateY(-6px); }
|
|
231
|
+
}
|
|
232
|
+
@keyframes fadeIn {
|
|
233
|
+
from { opacity: 0; transform: translateY(8px); }
|
|
234
|
+
to { opacity: 1; transform: translateY(0); }
|
|
235
|
+
}
|
|
236
|
+
` }),
|
|
237
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
238
|
+
"div",
|
|
239
|
+
{
|
|
240
|
+
style: {
|
|
241
|
+
position: "fixed",
|
|
242
|
+
bottom: 90,
|
|
243
|
+
right: 24,
|
|
244
|
+
width: 360,
|
|
245
|
+
maxWidth: "calc(100vw - 32px)",
|
|
246
|
+
height: 520,
|
|
247
|
+
maxHeight: "calc(100vh - 120px)",
|
|
248
|
+
background: colors.bg,
|
|
249
|
+
border: `1px solid ${colors.border}`,
|
|
250
|
+
borderRadius: 16,
|
|
251
|
+
boxShadow: "0 8px 40px rgba(0,0,0,0.18)",
|
|
252
|
+
display: "flex",
|
|
253
|
+
flexDirection: "column",
|
|
254
|
+
zIndex: 9998,
|
|
255
|
+
animation: "fadeIn 0.2s ease",
|
|
256
|
+
overflow: "hidden"
|
|
257
|
+
},
|
|
258
|
+
children: [
|
|
259
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
260
|
+
"div",
|
|
261
|
+
{
|
|
262
|
+
style: {
|
|
263
|
+
display: "flex",
|
|
264
|
+
alignItems: "center",
|
|
265
|
+
gap: 10,
|
|
266
|
+
padding: "14px 16px",
|
|
267
|
+
borderBottom: `1px solid ${colors.border}`,
|
|
268
|
+
background: colors.bg
|
|
269
|
+
},
|
|
270
|
+
children: [
|
|
271
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
272
|
+
"img",
|
|
273
|
+
{
|
|
274
|
+
src: logo,
|
|
275
|
+
alt: "logo",
|
|
276
|
+
style: { width: 28, height: 28, borderRadius: 6, objectFit: "cover" }
|
|
277
|
+
}
|
|
278
|
+
),
|
|
279
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontWeight: 600, fontSize: 15, color: colors.text, flex: 1 }, children: title }),
|
|
280
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
281
|
+
"button",
|
|
282
|
+
{
|
|
283
|
+
onClick: () => setOpen(false),
|
|
284
|
+
style: {
|
|
285
|
+
background: "none",
|
|
286
|
+
border: "none",
|
|
287
|
+
cursor: "pointer",
|
|
288
|
+
color: colors.textMuted,
|
|
289
|
+
padding: 4,
|
|
290
|
+
display: "flex",
|
|
291
|
+
alignItems: "center"
|
|
292
|
+
},
|
|
293
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CloseIcon, {})
|
|
294
|
+
}
|
|
295
|
+
)
|
|
296
|
+
]
|
|
297
|
+
}
|
|
298
|
+
),
|
|
299
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
300
|
+
"div",
|
|
301
|
+
{
|
|
302
|
+
style: {
|
|
303
|
+
flex: 1,
|
|
304
|
+
overflowY: "auto",
|
|
305
|
+
padding: 16,
|
|
306
|
+
display: "flex",
|
|
307
|
+
flexDirection: "column",
|
|
308
|
+
gap: 12
|
|
309
|
+
},
|
|
310
|
+
children: [
|
|
311
|
+
messages.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
312
|
+
"div",
|
|
313
|
+
{
|
|
314
|
+
style: {
|
|
315
|
+
background: colors.assistantBubble,
|
|
316
|
+
color: colors.assistantText,
|
|
317
|
+
padding: "10px 14px",
|
|
318
|
+
borderRadius: "18px 18px 18px 4px",
|
|
319
|
+
fontSize: 14,
|
|
320
|
+
lineHeight: 1.5,
|
|
321
|
+
maxWidth: "85%"
|
|
322
|
+
},
|
|
323
|
+
children: "\u{1F44B} Hi! How can I help you today?"
|
|
324
|
+
}
|
|
325
|
+
),
|
|
326
|
+
messages.map((msg) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
327
|
+
"div",
|
|
328
|
+
{
|
|
329
|
+
style: {
|
|
330
|
+
display: "flex",
|
|
331
|
+
justifyContent: msg.role === "user" ? "flex-end" : "flex-start"
|
|
332
|
+
},
|
|
333
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
334
|
+
"div",
|
|
335
|
+
{
|
|
336
|
+
style: {
|
|
337
|
+
maxWidth: "85%",
|
|
338
|
+
padding: "10px 14px",
|
|
339
|
+
borderRadius: msg.role === "user" ? "18px 18px 4px 18px" : "18px 18px 18px 4px",
|
|
340
|
+
background: msg.role === "user" ? primaryColor : colors.assistantBubble,
|
|
341
|
+
color: msg.role === "user" ? "#ffffff" : colors.assistantText,
|
|
342
|
+
fontSize: 14,
|
|
343
|
+
lineHeight: 1.6,
|
|
344
|
+
wordBreak: "break-word",
|
|
345
|
+
whiteSpace: "pre-wrap"
|
|
346
|
+
},
|
|
347
|
+
children: msg.content
|
|
348
|
+
}
|
|
349
|
+
)
|
|
350
|
+
},
|
|
351
|
+
msg.id
|
|
352
|
+
)),
|
|
353
|
+
isTyping && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TypingIndicator, { bg: colors.assistantBubble }),
|
|
354
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: 12, color: "#ef4444", textAlign: "center", margin: 0 }, children: error }),
|
|
355
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: messagesEndRef })
|
|
356
|
+
]
|
|
357
|
+
}
|
|
358
|
+
),
|
|
359
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
360
|
+
"div",
|
|
361
|
+
{
|
|
362
|
+
style: {
|
|
363
|
+
padding: "10px 12px",
|
|
364
|
+
borderTop: `1px solid ${colors.border}`,
|
|
365
|
+
display: "flex",
|
|
366
|
+
gap: 8,
|
|
367
|
+
alignItems: "flex-end",
|
|
368
|
+
background: colors.bg
|
|
369
|
+
},
|
|
370
|
+
children: [
|
|
371
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
372
|
+
"textarea",
|
|
373
|
+
{
|
|
374
|
+
ref: inputRef,
|
|
375
|
+
value: input,
|
|
376
|
+
onChange: (e) => setInput(e.target.value),
|
|
377
|
+
onKeyDown: handleKeyDown,
|
|
378
|
+
placeholder: "Ask a question...",
|
|
379
|
+
rows: 1,
|
|
380
|
+
disabled: isTyping,
|
|
381
|
+
style: {
|
|
382
|
+
flex: 1,
|
|
383
|
+
resize: "none",
|
|
384
|
+
border: `1px solid ${colors.border}`,
|
|
385
|
+
borderRadius: 10,
|
|
386
|
+
padding: "8px 12px",
|
|
387
|
+
fontSize: 14,
|
|
388
|
+
lineHeight: 1.5,
|
|
389
|
+
background: colors.inputBg,
|
|
390
|
+
color: colors.text,
|
|
391
|
+
outline: "none",
|
|
392
|
+
fontFamily: "inherit",
|
|
393
|
+
maxHeight: 100,
|
|
394
|
+
overflowY: "auto"
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
),
|
|
398
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
399
|
+
"button",
|
|
400
|
+
{
|
|
401
|
+
onClick: sendMessage,
|
|
402
|
+
disabled: !input.trim() || isTyping,
|
|
403
|
+
style: {
|
|
404
|
+
width: 38,
|
|
405
|
+
height: 38,
|
|
406
|
+
borderRadius: 10,
|
|
407
|
+
background: primaryColor,
|
|
408
|
+
border: "none",
|
|
409
|
+
cursor: "pointer",
|
|
410
|
+
display: "flex",
|
|
411
|
+
alignItems: "center",
|
|
412
|
+
justifyContent: "center",
|
|
413
|
+
color: "#ffffff",
|
|
414
|
+
opacity: !input.trim() || isTyping ? 0.4 : 1,
|
|
415
|
+
flexShrink: 0,
|
|
416
|
+
transition: "opacity 0.15s"
|
|
417
|
+
},
|
|
418
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SendIcon, {})
|
|
419
|
+
}
|
|
420
|
+
)
|
|
421
|
+
]
|
|
422
|
+
}
|
|
423
|
+
)
|
|
424
|
+
]
|
|
425
|
+
}
|
|
426
|
+
),
|
|
427
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
428
|
+
"button",
|
|
429
|
+
{
|
|
430
|
+
onClick: () => setOpen((prev) => !prev),
|
|
431
|
+
style: {
|
|
432
|
+
position: "fixed",
|
|
433
|
+
bottom: 24,
|
|
434
|
+
right: 24,
|
|
435
|
+
width: 56,
|
|
436
|
+
height: 56,
|
|
437
|
+
borderRadius: "50%",
|
|
438
|
+
background: primaryColor,
|
|
439
|
+
border: "none",
|
|
440
|
+
cursor: "pointer",
|
|
441
|
+
display: "flex",
|
|
442
|
+
alignItems: "center",
|
|
443
|
+
justifyContent: "center",
|
|
444
|
+
color: "#ffffff",
|
|
445
|
+
boxShadow: "0 4px 20px rgba(0,0,0,0.2)",
|
|
446
|
+
zIndex: 9999,
|
|
447
|
+
transition: "transform 0.15s, box-shadow 0.15s"
|
|
448
|
+
},
|
|
449
|
+
onMouseEnter: (e) => {
|
|
450
|
+
e.currentTarget.style.transform = "scale(1.08)";
|
|
451
|
+
e.currentTarget.style.boxShadow = "0 6px 24px rgba(0,0,0,0.28)";
|
|
452
|
+
},
|
|
453
|
+
onMouseLeave: (e) => {
|
|
454
|
+
e.currentTarget.style.transform = "scale(1)";
|
|
455
|
+
e.currentTarget.style.boxShadow = "0 4px 20px rgba(0,0,0,0.2)";
|
|
456
|
+
},
|
|
457
|
+
"aria-label": open ? "Close support chat" : "Open support chat",
|
|
458
|
+
children: open ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CloseIcon, { size: 22 }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChatIcon, { size: 24 })
|
|
459
|
+
}
|
|
460
|
+
)
|
|
461
|
+
] });
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// src/useClaudeSupport.tsx
|
|
465
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
466
|
+
function useClaudeSupport(options) {
|
|
467
|
+
const { endpoint, knowledge, branding = {} } = options;
|
|
468
|
+
const SupportWidget = () => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
469
|
+
SupportWidgetComponent,
|
|
470
|
+
{
|
|
471
|
+
endpoint,
|
|
472
|
+
knowledge,
|
|
473
|
+
branding
|
|
474
|
+
}
|
|
475
|
+
);
|
|
476
|
+
SupportWidget.displayName = "ClaudeSupport.Widget";
|
|
477
|
+
return { SupportWidget };
|
|
478
|
+
}
|
|
479
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
480
|
+
0 && (module.exports = {
|
|
481
|
+
useClaudeSupport
|
|
482
|
+
});
|
|
483
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/SupportWidget.tsx","../src/useClaudeSupport.tsx"],"sourcesContent":["export { useClaudeSupport } from \"./useClaudeSupport\"\nexport type { ClaudeSupport } from \"./useClaudeSupport\"","\"use client\"\n\nimport React, { useState, useRef, useEffect, useCallback } from \"react\"\nimport type { ClaudeSupport } from \"./useClaudeSupport\"\n\n// ─── Claude logo ──────────────────────────────────────────────────────────────\n\nconst CLAUDE_LOGO =\n \"data:image/svg+xml;base64,\" +\n btoa(\n `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 48 48\" fill=\"none\">\n <rect width=\"48\" height=\"48\" rx=\"12\" fill=\"#D97757\"/>\n <path d=\"M32.16 13H28.7l-7.4 21.82h3.22l1.68-5.18h7.56l1.68 5.18h3.32L32.16 13zm-5.06 13.94 2.96-9.12 2.96 9.12h-5.92zM18.3 13h-3.46L11 22.06 7.16 13H3.7l5.96 13.44L3.7 39h3.46l4.62-10.5L16.4 39h3.46l-6-12.56L18.3 13z\" fill=\"white\"/>\n</svg>`\n )\n\n// ─── Icons ────────────────────────────────────────────────────────────────────\n\nfunction ChatIcon({ size = 24 }: { size?: number }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M12 2C6.477 2 2 6.477 2 12c0 1.89.525 3.66 1.438 5.168L2.546 21.16a.5.5 0 00.628.628l3.992-.892A9.96 9.96 0 0012 22c5.523 0 10-4.477 10-10S17.523 2 12 2z\" />\n </svg>\n )\n}\n\nfunction CloseIcon({ size = 18 }: { size?: number }) {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n )\n}\n\nfunction SendIcon({ size = 18 }: { size?: number }) {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\" />\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\" />\n </svg>\n )\n}\n\n// ─── Typing indicator ─────────────────────────────────────────────────────────\n\nfunction TypingIndicator({ bg }: { bg: string }) {\n return (\n <div\n style={{\n display: \"flex\",\n gap: 4,\n padding: \"10px 14px\",\n background: bg,\n borderRadius: \"18px 18px 18px 4px\",\n width: \"fit-content\",\n alignItems: \"center\",\n }}\n >\n {[0, 1, 2].map((i) => (\n <span\n key={i}\n style={{\n width: 7,\n height: 7,\n borderRadius: \"50%\",\n background: \"#9ca3af\",\n display: \"inline-block\",\n animation: \"bounce 1.2s infinite\",\n animationDelay: `${i * 0.2}s`,\n }}\n />\n ))}\n </div>\n )\n}\n\n// ─── Theme resolver ───────────────────────────────────────────────────────────\n\nfunction useResolvedTheme(theme: ClaudeSupport.Theme): \"light\" | \"dark\" {\n const [resolved, setResolved] = useState<\"light\" | \"dark\">(\"light\")\n\n useEffect(() => {\n if (theme === \"light\" || theme === \"dark\") {\n setResolved(theme)\n return\n }\n\n const checkTheme = () => {\n const html = document.documentElement\n const dataTheme = html.getAttribute(\"data-theme\")\n const classList = html.classList\n\n if (dataTheme === \"dark\" || classList.contains(\"dark\")) {\n setResolved(\"dark\")\n return\n }\n if (dataTheme === \"light\" || classList.contains(\"light\")) {\n setResolved(\"light\")\n return\n }\n\n const prefersDark = window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n setResolved(prefersDark ? \"dark\" : \"light\")\n }\n\n checkTheme()\n\n const observer = new MutationObserver(checkTheme)\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"class\", \"data-theme\", \"style\"],\n })\n\n const mq = window.matchMedia(\"(prefers-color-scheme: dark)\")\n mq.addEventListener(\"change\", checkTheme)\n\n return () => {\n observer.disconnect()\n mq.removeEventListener(\"change\", checkTheme)\n }\n }, [theme])\n\n return resolved\n}\n\n// ─── Widget ───────────────────────────────────────────────────────────────────\n\ninterface SupportWidgetProps {\n endpoint: string\n knowledge: string\n branding: ClaudeSupport.Branding\n}\n\nexport function SupportWidgetComponent({\n endpoint,\n knowledge,\n branding,\n}: SupportWidgetProps) {\n const {\n theme = \"system\",\n primaryColor = \"#D97757\",\n logo = CLAUDE_LOGO,\n title = \"Claude Support\",\n } = branding\n\n const resolvedTheme = useResolvedTheme(theme)\n const isDark = resolvedTheme === \"dark\"\n\n const colors = {\n bg: isDark ? \"#1a1a1a\" : \"#ffffff\",\n border: isDark ? \"#333333\" : \"#e5e7eb\",\n text: isDark ? \"#f1f1f1\" : \"#111111\",\n textMuted: isDark ? \"#9ca3af\" : \"#6b7280\",\n inputBg: isDark ? \"#2a2a2a\" : \"#ffffff\",\n assistantBubble: isDark ? \"#2a2a2a\" : \"#f3f4f6\",\n assistantText: isDark ? \"#f1f1f1\" : \"#111111\",\n }\n\n const [open, setOpen] = useState(false)\n const [messages, setMessages] = useState<ClaudeSupport.Message[]>([])\n const [input, setInput] = useState(\"\")\n const [isTyping, setIsTyping] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const messagesEndRef = useRef<HTMLDivElement>(null)\n const inputRef = useRef<HTMLTextAreaElement>(null)\n\n useEffect(() => {\n messagesEndRef.current?.scrollIntoView({ behavior: \"smooth\" })\n }, [messages, isTyping])\n\n useEffect(() => {\n if (open) setTimeout(() => inputRef.current?.focus(), 100)\n }, [open])\n\n useEffect(() => {\n const handler = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") setOpen(false)\n }\n document.addEventListener(\"keydown\", handler)\n return () => document.removeEventListener(\"keydown\", handler)\n }, [])\n\n const sendMessage = useCallback(async () => {\n if (!input.trim() || isTyping) return\n setError(null)\n\n const userMessage: ClaudeSupport.Message = {\n id: crypto.randomUUID(),\n role: \"user\",\n content: input.trim(),\n timestamp: Date.now(),\n }\n\n const history = messages.map((m) => ({ role: m.role, content: m.content }))\n setMessages((prev) => [...prev, userMessage])\n setInput(\"\")\n setIsTyping(true)\n\n try {\n const res = await fetch(endpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ message: userMessage.content, history, knowledge }),\n })\n\n if (!res.ok) throw new Error(`Request failed: ${res.status}`)\n const data = await res.json()\n\n const assistantMessage: ClaudeSupport.Message = {\n id: crypto.randomUUID(),\n role: \"assistant\",\n content: data.reply,\n timestamp: Date.now(),\n }\n\n setMessages((prev) => [...prev, assistantMessage])\n } catch {\n setError(\"Something went wrong. Please try again.\")\n } finally {\n setIsTyping(false)\n }\n }, [input, isTyping, messages, endpoint, knowledge])\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault()\n sendMessage()\n }\n }\n\n return (\n <>\n <style>{`\n @keyframes bounce {\n 0%, 60%, 100% { transform: translateY(0); }\n 30% { transform: translateY(-6px); }\n }\n @keyframes fadeIn {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n }\n `}</style>\n\n {open && (\n <div\n style={{\n position: \"fixed\",\n bottom: 90,\n right: 24,\n width: 360,\n maxWidth: \"calc(100vw - 32px)\",\n height: 520,\n maxHeight: \"calc(100vh - 120px)\",\n background: colors.bg,\n border: `1px solid ${colors.border}`,\n borderRadius: 16,\n boxShadow: \"0 8px 40px rgba(0,0,0,0.18)\",\n display: \"flex\",\n flexDirection: \"column\",\n zIndex: 9998,\n animation: \"fadeIn 0.2s ease\",\n overflow: \"hidden\",\n }}\n >\n {/* Header */}\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 10,\n padding: \"14px 16px\",\n borderBottom: `1px solid ${colors.border}`,\n background: colors.bg,\n }}\n >\n <img\n src={logo}\n alt=\"logo\"\n style={{ width: 28, height: 28, borderRadius: 6, objectFit: \"cover\" }}\n />\n <span style={{ fontWeight: 600, fontSize: 15, color: colors.text, flex: 1 }}>\n {title}\n </span>\n <button\n onClick={() => setOpen(false)}\n style={{\n background: \"none\",\n border: \"none\",\n cursor: \"pointer\",\n color: colors.textMuted,\n padding: 4,\n display: \"flex\",\n alignItems: \"center\",\n }}\n >\n <CloseIcon />\n </button>\n </div>\n\n {/* Messages */}\n <div\n style={{\n flex: 1,\n overflowY: \"auto\",\n padding: 16,\n display: \"flex\",\n flexDirection: \"column\",\n gap: 12,\n }}\n >\n {messages.length === 0 && (\n <div\n style={{\n background: colors.assistantBubble,\n color: colors.assistantText,\n padding: \"10px 14px\",\n borderRadius: \"18px 18px 18px 4px\",\n fontSize: 14,\n lineHeight: 1.5,\n maxWidth: \"85%\",\n }}\n >\n 👋 Hi! How can I help you today?\n </div>\n )}\n\n {messages.map((msg) => (\n <div\n key={msg.id}\n style={{\n display: \"flex\",\n justifyContent: msg.role === \"user\" ? \"flex-end\" : \"flex-start\",\n }}\n >\n <div\n style={{\n maxWidth: \"85%\",\n padding: \"10px 14px\",\n borderRadius:\n msg.role === \"user\"\n ? \"18px 18px 4px 18px\"\n : \"18px 18px 18px 4px\",\n background:\n msg.role === \"user\" ? primaryColor : colors.assistantBubble,\n color: msg.role === \"user\" ? \"#ffffff\" : colors.assistantText,\n fontSize: 14,\n lineHeight: 1.6,\n wordBreak: \"break-word\",\n whiteSpace: \"pre-wrap\",\n }}\n >\n {msg.content}\n </div>\n </div>\n ))}\n\n {isTyping && <TypingIndicator bg={colors.assistantBubble} />}\n\n {error && (\n <p style={{ fontSize: 12, color: \"#ef4444\", textAlign: \"center\", margin: 0 }}>\n {error}\n </p>\n )}\n\n <div ref={messagesEndRef} />\n </div>\n\n {/* Input */}\n <div\n style={{\n padding: \"10px 12px\",\n borderTop: `1px solid ${colors.border}`,\n display: \"flex\",\n gap: 8,\n alignItems: \"flex-end\",\n background: colors.bg,\n }}\n >\n <textarea\n ref={inputRef}\n value={input}\n onChange={(e) => setInput(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"Ask a question...\"\n rows={1}\n disabled={isTyping}\n style={{\n flex: 1,\n resize: \"none\",\n border: `1px solid ${colors.border}`,\n borderRadius: 10,\n padding: \"8px 12px\",\n fontSize: 14,\n lineHeight: 1.5,\n background: colors.inputBg,\n color: colors.text,\n outline: \"none\",\n fontFamily: \"inherit\",\n maxHeight: 100,\n overflowY: \"auto\",\n }}\n />\n <button\n onClick={sendMessage}\n disabled={!input.trim() || isTyping}\n style={{\n width: 38,\n height: 38,\n borderRadius: 10,\n background: primaryColor,\n border: \"none\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n color: \"#ffffff\",\n opacity: !input.trim() || isTyping ? 0.4 : 1,\n flexShrink: 0,\n transition: \"opacity 0.15s\",\n }}\n >\n <SendIcon />\n </button>\n </div>\n </div>\n )}\n\n {/* Trigger button */}\n <button\n onClick={() => setOpen((prev) => !prev)}\n style={{\n position: \"fixed\",\n bottom: 24,\n right: 24,\n width: 56,\n height: 56,\n borderRadius: \"50%\",\n background: primaryColor,\n border: \"none\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n color: \"#ffffff\",\n boxShadow: \"0 4px 20px rgba(0,0,0,0.2)\",\n zIndex: 9999,\n transition: \"transform 0.15s, box-shadow 0.15s\",\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.transform = \"scale(1.08)\"\n e.currentTarget.style.boxShadow = \"0 6px 24px rgba(0,0,0,0.28)\"\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.transform = \"scale(1)\"\n e.currentTarget.style.boxShadow = \"0 4px 20px rgba(0,0,0,0.2)\"\n }}\n aria-label={open ? \"Close support chat\" : \"Open support chat\"}\n >\n {open ? <CloseIcon size={22} /> : <ChatIcon size={24} />}\n </button>\n </>\n )\n}","\"use client\"\n\nimport React from \"react\"\nimport { SupportWidgetComponent } from \"./SupportWidget\"\n\n// ─── Namespace ────────────────────────────────────────────────────────────────\n\nexport namespace ClaudeSupport {\n export type Theme = \"light\" | \"dark\" | \"system\"\n\n export interface Branding {\n theme?: Theme\n primaryColor?: string\n logo?: string\n title?: string\n }\n\n export interface Message {\n id: string\n role: \"user\" | \"assistant\"\n content: string\n timestamp: number\n }\n\n export interface Options {\n endpoint: string\n knowledge: string\n branding?: Branding\n }\n\n export interface Return {\n SupportWidget: React.FC\n }\n}\n\n// ─── Hook ─────────────────────────────────────────────────────────────────────\n\nexport function useClaudeSupport(options: ClaudeSupport.Options): ClaudeSupport.Return {\n const { endpoint, knowledge, branding = {} } = options\n\n const SupportWidget: React.FC = () => (\n <SupportWidgetComponent\n endpoint={endpoint}\n knowledge={knowledge}\n branding={branding}\n />\n )\n\n SupportWidget.displayName = \"ClaudeSupport.Widget\"\n\n return { SupportWidget }\n}"],"mappings":"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","names":["import_jsx_runtime"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
declare namespace ClaudeSupport {
|
|
4
|
+
type Theme = "light" | "dark" | "system";
|
|
5
|
+
interface Branding {
|
|
6
|
+
theme?: Theme;
|
|
7
|
+
primaryColor?: string;
|
|
8
|
+
logo?: string;
|
|
9
|
+
title?: string;
|
|
10
|
+
}
|
|
11
|
+
interface Message {
|
|
12
|
+
id: string;
|
|
13
|
+
role: "user" | "assistant";
|
|
14
|
+
content: string;
|
|
15
|
+
timestamp: number;
|
|
16
|
+
}
|
|
17
|
+
interface Options {
|
|
18
|
+
endpoint: string;
|
|
19
|
+
knowledge: string;
|
|
20
|
+
branding?: Branding;
|
|
21
|
+
}
|
|
22
|
+
interface Return {
|
|
23
|
+
SupportWidget: React.FC;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
declare function useClaudeSupport(options: ClaudeSupport.Options): ClaudeSupport.Return;
|
|
27
|
+
|
|
28
|
+
export { ClaudeSupport, useClaudeSupport };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
declare namespace ClaudeSupport {
|
|
4
|
+
type Theme = "light" | "dark" | "system";
|
|
5
|
+
interface Branding {
|
|
6
|
+
theme?: Theme;
|
|
7
|
+
primaryColor?: string;
|
|
8
|
+
logo?: string;
|
|
9
|
+
title?: string;
|
|
10
|
+
}
|
|
11
|
+
interface Message {
|
|
12
|
+
id: string;
|
|
13
|
+
role: "user" | "assistant";
|
|
14
|
+
content: string;
|
|
15
|
+
timestamp: number;
|
|
16
|
+
}
|
|
17
|
+
interface Options {
|
|
18
|
+
endpoint: string;
|
|
19
|
+
knowledge: string;
|
|
20
|
+
branding?: Branding;
|
|
21
|
+
}
|
|
22
|
+
interface Return {
|
|
23
|
+
SupportWidget: React.FC;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
declare function useClaudeSupport(options: ClaudeSupport.Options): ClaudeSupport.Return;
|
|
27
|
+
|
|
28
|
+
export { ClaudeSupport, useClaudeSupport };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
// src/SupportWidget.tsx
|
|
2
|
+
import { useState, useRef, useEffect, useCallback } from "react";
|
|
3
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
var CLAUDE_LOGO = "data:image/svg+xml;base64," + btoa(
|
|
5
|
+
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" fill="none">
|
|
6
|
+
<rect width="48" height="48" rx="12" fill="#D97757"/>
|
|
7
|
+
<path d="M32.16 13H28.7l-7.4 21.82h3.22l1.68-5.18h7.56l1.68 5.18h3.32L32.16 13zm-5.06 13.94 2.96-9.12 2.96 9.12h-5.92zM18.3 13h-3.46L11 22.06 7.16 13H3.7l5.96 13.44L3.7 39h3.46l4.62-10.5L16.4 39h3.46l-6-12.56L18.3 13z" fill="white"/>
|
|
8
|
+
</svg>`
|
|
9
|
+
);
|
|
10
|
+
function ChatIcon({ size = 24 }) {
|
|
11
|
+
return /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M12 2C6.477 2 2 6.477 2 12c0 1.89.525 3.66 1.438 5.168L2.546 21.16a.5.5 0 00.628.628l3.992-.892A9.96 9.96 0 0012 22c5.523 0 10-4.477 10-10S17.523 2 12 2z" }) });
|
|
12
|
+
}
|
|
13
|
+
function CloseIcon({ size = 18 }) {
|
|
14
|
+
return /* @__PURE__ */ jsxs(
|
|
15
|
+
"svg",
|
|
16
|
+
{
|
|
17
|
+
width: size,
|
|
18
|
+
height: size,
|
|
19
|
+
viewBox: "0 0 24 24",
|
|
20
|
+
fill: "none",
|
|
21
|
+
stroke: "currentColor",
|
|
22
|
+
strokeWidth: 2,
|
|
23
|
+
strokeLinecap: "round",
|
|
24
|
+
children: [
|
|
25
|
+
/* @__PURE__ */ jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
26
|
+
/* @__PURE__ */ jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
function SendIcon({ size = 18 }) {
|
|
32
|
+
return /* @__PURE__ */ jsxs(
|
|
33
|
+
"svg",
|
|
34
|
+
{
|
|
35
|
+
width: size,
|
|
36
|
+
height: size,
|
|
37
|
+
viewBox: "0 0 24 24",
|
|
38
|
+
fill: "none",
|
|
39
|
+
stroke: "currentColor",
|
|
40
|
+
strokeWidth: 2,
|
|
41
|
+
strokeLinecap: "round",
|
|
42
|
+
strokeLinejoin: "round",
|
|
43
|
+
children: [
|
|
44
|
+
/* @__PURE__ */ jsx("line", { x1: "22", y1: "2", x2: "11", y2: "13" }),
|
|
45
|
+
/* @__PURE__ */ jsx("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
function TypingIndicator({ bg }) {
|
|
51
|
+
return /* @__PURE__ */ jsx(
|
|
52
|
+
"div",
|
|
53
|
+
{
|
|
54
|
+
style: {
|
|
55
|
+
display: "flex",
|
|
56
|
+
gap: 4,
|
|
57
|
+
padding: "10px 14px",
|
|
58
|
+
background: bg,
|
|
59
|
+
borderRadius: "18px 18px 18px 4px",
|
|
60
|
+
width: "fit-content",
|
|
61
|
+
alignItems: "center"
|
|
62
|
+
},
|
|
63
|
+
children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx(
|
|
64
|
+
"span",
|
|
65
|
+
{
|
|
66
|
+
style: {
|
|
67
|
+
width: 7,
|
|
68
|
+
height: 7,
|
|
69
|
+
borderRadius: "50%",
|
|
70
|
+
background: "#9ca3af",
|
|
71
|
+
display: "inline-block",
|
|
72
|
+
animation: "bounce 1.2s infinite",
|
|
73
|
+
animationDelay: `${i * 0.2}s`
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
i
|
|
77
|
+
))
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
function useResolvedTheme(theme) {
|
|
82
|
+
const [resolved, setResolved] = useState("light");
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
if (theme === "light" || theme === "dark") {
|
|
85
|
+
setResolved(theme);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const checkTheme = () => {
|
|
89
|
+
const html = document.documentElement;
|
|
90
|
+
const dataTheme = html.getAttribute("data-theme");
|
|
91
|
+
const classList = html.classList;
|
|
92
|
+
if (dataTheme === "dark" || classList.contains("dark")) {
|
|
93
|
+
setResolved("dark");
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (dataTheme === "light" || classList.contains("light")) {
|
|
97
|
+
setResolved("light");
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
101
|
+
setResolved(prefersDark ? "dark" : "light");
|
|
102
|
+
};
|
|
103
|
+
checkTheme();
|
|
104
|
+
const observer = new MutationObserver(checkTheme);
|
|
105
|
+
observer.observe(document.documentElement, {
|
|
106
|
+
attributes: true,
|
|
107
|
+
attributeFilter: ["class", "data-theme", "style"]
|
|
108
|
+
});
|
|
109
|
+
const mq = window.matchMedia("(prefers-color-scheme: dark)");
|
|
110
|
+
mq.addEventListener("change", checkTheme);
|
|
111
|
+
return () => {
|
|
112
|
+
observer.disconnect();
|
|
113
|
+
mq.removeEventListener("change", checkTheme);
|
|
114
|
+
};
|
|
115
|
+
}, [theme]);
|
|
116
|
+
return resolved;
|
|
117
|
+
}
|
|
118
|
+
function SupportWidgetComponent({
|
|
119
|
+
endpoint,
|
|
120
|
+
knowledge,
|
|
121
|
+
branding
|
|
122
|
+
}) {
|
|
123
|
+
const {
|
|
124
|
+
theme = "system",
|
|
125
|
+
primaryColor = "#D97757",
|
|
126
|
+
logo = CLAUDE_LOGO,
|
|
127
|
+
title = "Claude Support"
|
|
128
|
+
} = branding;
|
|
129
|
+
const resolvedTheme = useResolvedTheme(theme);
|
|
130
|
+
const isDark = resolvedTheme === "dark";
|
|
131
|
+
const colors = {
|
|
132
|
+
bg: isDark ? "#1a1a1a" : "#ffffff",
|
|
133
|
+
border: isDark ? "#333333" : "#e5e7eb",
|
|
134
|
+
text: isDark ? "#f1f1f1" : "#111111",
|
|
135
|
+
textMuted: isDark ? "#9ca3af" : "#6b7280",
|
|
136
|
+
inputBg: isDark ? "#2a2a2a" : "#ffffff",
|
|
137
|
+
assistantBubble: isDark ? "#2a2a2a" : "#f3f4f6",
|
|
138
|
+
assistantText: isDark ? "#f1f1f1" : "#111111"
|
|
139
|
+
};
|
|
140
|
+
const [open, setOpen] = useState(false);
|
|
141
|
+
const [messages, setMessages] = useState([]);
|
|
142
|
+
const [input, setInput] = useState("");
|
|
143
|
+
const [isTyping, setIsTyping] = useState(false);
|
|
144
|
+
const [error, setError] = useState(null);
|
|
145
|
+
const messagesEndRef = useRef(null);
|
|
146
|
+
const inputRef = useRef(null);
|
|
147
|
+
useEffect(() => {
|
|
148
|
+
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
149
|
+
}, [messages, isTyping]);
|
|
150
|
+
useEffect(() => {
|
|
151
|
+
if (open) setTimeout(() => inputRef.current?.focus(), 100);
|
|
152
|
+
}, [open]);
|
|
153
|
+
useEffect(() => {
|
|
154
|
+
const handler = (e) => {
|
|
155
|
+
if (e.key === "Escape") setOpen(false);
|
|
156
|
+
};
|
|
157
|
+
document.addEventListener("keydown", handler);
|
|
158
|
+
return () => document.removeEventListener("keydown", handler);
|
|
159
|
+
}, []);
|
|
160
|
+
const sendMessage = useCallback(async () => {
|
|
161
|
+
if (!input.trim() || isTyping) return;
|
|
162
|
+
setError(null);
|
|
163
|
+
const userMessage = {
|
|
164
|
+
id: crypto.randomUUID(),
|
|
165
|
+
role: "user",
|
|
166
|
+
content: input.trim(),
|
|
167
|
+
timestamp: Date.now()
|
|
168
|
+
};
|
|
169
|
+
const history = messages.map((m) => ({ role: m.role, content: m.content }));
|
|
170
|
+
setMessages((prev) => [...prev, userMessage]);
|
|
171
|
+
setInput("");
|
|
172
|
+
setIsTyping(true);
|
|
173
|
+
try {
|
|
174
|
+
const res = await fetch(endpoint, {
|
|
175
|
+
method: "POST",
|
|
176
|
+
headers: { "Content-Type": "application/json" },
|
|
177
|
+
body: JSON.stringify({ message: userMessage.content, history, knowledge })
|
|
178
|
+
});
|
|
179
|
+
if (!res.ok) throw new Error(`Request failed: ${res.status}`);
|
|
180
|
+
const data = await res.json();
|
|
181
|
+
const assistantMessage = {
|
|
182
|
+
id: crypto.randomUUID(),
|
|
183
|
+
role: "assistant",
|
|
184
|
+
content: data.reply,
|
|
185
|
+
timestamp: Date.now()
|
|
186
|
+
};
|
|
187
|
+
setMessages((prev) => [...prev, assistantMessage]);
|
|
188
|
+
} catch {
|
|
189
|
+
setError("Something went wrong. Please try again.");
|
|
190
|
+
} finally {
|
|
191
|
+
setIsTyping(false);
|
|
192
|
+
}
|
|
193
|
+
}, [input, isTyping, messages, endpoint, knowledge]);
|
|
194
|
+
const handleKeyDown = (e) => {
|
|
195
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
196
|
+
e.preventDefault();
|
|
197
|
+
sendMessage();
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
201
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
202
|
+
@keyframes bounce {
|
|
203
|
+
0%, 60%, 100% { transform: translateY(0); }
|
|
204
|
+
30% { transform: translateY(-6px); }
|
|
205
|
+
}
|
|
206
|
+
@keyframes fadeIn {
|
|
207
|
+
from { opacity: 0; transform: translateY(8px); }
|
|
208
|
+
to { opacity: 1; transform: translateY(0); }
|
|
209
|
+
}
|
|
210
|
+
` }),
|
|
211
|
+
open && /* @__PURE__ */ jsxs(
|
|
212
|
+
"div",
|
|
213
|
+
{
|
|
214
|
+
style: {
|
|
215
|
+
position: "fixed",
|
|
216
|
+
bottom: 90,
|
|
217
|
+
right: 24,
|
|
218
|
+
width: 360,
|
|
219
|
+
maxWidth: "calc(100vw - 32px)",
|
|
220
|
+
height: 520,
|
|
221
|
+
maxHeight: "calc(100vh - 120px)",
|
|
222
|
+
background: colors.bg,
|
|
223
|
+
border: `1px solid ${colors.border}`,
|
|
224
|
+
borderRadius: 16,
|
|
225
|
+
boxShadow: "0 8px 40px rgba(0,0,0,0.18)",
|
|
226
|
+
display: "flex",
|
|
227
|
+
flexDirection: "column",
|
|
228
|
+
zIndex: 9998,
|
|
229
|
+
animation: "fadeIn 0.2s ease",
|
|
230
|
+
overflow: "hidden"
|
|
231
|
+
},
|
|
232
|
+
children: [
|
|
233
|
+
/* @__PURE__ */ jsxs(
|
|
234
|
+
"div",
|
|
235
|
+
{
|
|
236
|
+
style: {
|
|
237
|
+
display: "flex",
|
|
238
|
+
alignItems: "center",
|
|
239
|
+
gap: 10,
|
|
240
|
+
padding: "14px 16px",
|
|
241
|
+
borderBottom: `1px solid ${colors.border}`,
|
|
242
|
+
background: colors.bg
|
|
243
|
+
},
|
|
244
|
+
children: [
|
|
245
|
+
/* @__PURE__ */ jsx(
|
|
246
|
+
"img",
|
|
247
|
+
{
|
|
248
|
+
src: logo,
|
|
249
|
+
alt: "logo",
|
|
250
|
+
style: { width: 28, height: 28, borderRadius: 6, objectFit: "cover" }
|
|
251
|
+
}
|
|
252
|
+
),
|
|
253
|
+
/* @__PURE__ */ jsx("span", { style: { fontWeight: 600, fontSize: 15, color: colors.text, flex: 1 }, children: title }),
|
|
254
|
+
/* @__PURE__ */ jsx(
|
|
255
|
+
"button",
|
|
256
|
+
{
|
|
257
|
+
onClick: () => setOpen(false),
|
|
258
|
+
style: {
|
|
259
|
+
background: "none",
|
|
260
|
+
border: "none",
|
|
261
|
+
cursor: "pointer",
|
|
262
|
+
color: colors.textMuted,
|
|
263
|
+
padding: 4,
|
|
264
|
+
display: "flex",
|
|
265
|
+
alignItems: "center"
|
|
266
|
+
},
|
|
267
|
+
children: /* @__PURE__ */ jsx(CloseIcon, {})
|
|
268
|
+
}
|
|
269
|
+
)
|
|
270
|
+
]
|
|
271
|
+
}
|
|
272
|
+
),
|
|
273
|
+
/* @__PURE__ */ jsxs(
|
|
274
|
+
"div",
|
|
275
|
+
{
|
|
276
|
+
style: {
|
|
277
|
+
flex: 1,
|
|
278
|
+
overflowY: "auto",
|
|
279
|
+
padding: 16,
|
|
280
|
+
display: "flex",
|
|
281
|
+
flexDirection: "column",
|
|
282
|
+
gap: 12
|
|
283
|
+
},
|
|
284
|
+
children: [
|
|
285
|
+
messages.length === 0 && /* @__PURE__ */ jsx(
|
|
286
|
+
"div",
|
|
287
|
+
{
|
|
288
|
+
style: {
|
|
289
|
+
background: colors.assistantBubble,
|
|
290
|
+
color: colors.assistantText,
|
|
291
|
+
padding: "10px 14px",
|
|
292
|
+
borderRadius: "18px 18px 18px 4px",
|
|
293
|
+
fontSize: 14,
|
|
294
|
+
lineHeight: 1.5,
|
|
295
|
+
maxWidth: "85%"
|
|
296
|
+
},
|
|
297
|
+
children: "\u{1F44B} Hi! How can I help you today?"
|
|
298
|
+
}
|
|
299
|
+
),
|
|
300
|
+
messages.map((msg) => /* @__PURE__ */ jsx(
|
|
301
|
+
"div",
|
|
302
|
+
{
|
|
303
|
+
style: {
|
|
304
|
+
display: "flex",
|
|
305
|
+
justifyContent: msg.role === "user" ? "flex-end" : "flex-start"
|
|
306
|
+
},
|
|
307
|
+
children: /* @__PURE__ */ jsx(
|
|
308
|
+
"div",
|
|
309
|
+
{
|
|
310
|
+
style: {
|
|
311
|
+
maxWidth: "85%",
|
|
312
|
+
padding: "10px 14px",
|
|
313
|
+
borderRadius: msg.role === "user" ? "18px 18px 4px 18px" : "18px 18px 18px 4px",
|
|
314
|
+
background: msg.role === "user" ? primaryColor : colors.assistantBubble,
|
|
315
|
+
color: msg.role === "user" ? "#ffffff" : colors.assistantText,
|
|
316
|
+
fontSize: 14,
|
|
317
|
+
lineHeight: 1.6,
|
|
318
|
+
wordBreak: "break-word",
|
|
319
|
+
whiteSpace: "pre-wrap"
|
|
320
|
+
},
|
|
321
|
+
children: msg.content
|
|
322
|
+
}
|
|
323
|
+
)
|
|
324
|
+
},
|
|
325
|
+
msg.id
|
|
326
|
+
)),
|
|
327
|
+
isTyping && /* @__PURE__ */ jsx(TypingIndicator, { bg: colors.assistantBubble }),
|
|
328
|
+
error && /* @__PURE__ */ jsx("p", { style: { fontSize: 12, color: "#ef4444", textAlign: "center", margin: 0 }, children: error }),
|
|
329
|
+
/* @__PURE__ */ jsx("div", { ref: messagesEndRef })
|
|
330
|
+
]
|
|
331
|
+
}
|
|
332
|
+
),
|
|
333
|
+
/* @__PURE__ */ jsxs(
|
|
334
|
+
"div",
|
|
335
|
+
{
|
|
336
|
+
style: {
|
|
337
|
+
padding: "10px 12px",
|
|
338
|
+
borderTop: `1px solid ${colors.border}`,
|
|
339
|
+
display: "flex",
|
|
340
|
+
gap: 8,
|
|
341
|
+
alignItems: "flex-end",
|
|
342
|
+
background: colors.bg
|
|
343
|
+
},
|
|
344
|
+
children: [
|
|
345
|
+
/* @__PURE__ */ jsx(
|
|
346
|
+
"textarea",
|
|
347
|
+
{
|
|
348
|
+
ref: inputRef,
|
|
349
|
+
value: input,
|
|
350
|
+
onChange: (e) => setInput(e.target.value),
|
|
351
|
+
onKeyDown: handleKeyDown,
|
|
352
|
+
placeholder: "Ask a question...",
|
|
353
|
+
rows: 1,
|
|
354
|
+
disabled: isTyping,
|
|
355
|
+
style: {
|
|
356
|
+
flex: 1,
|
|
357
|
+
resize: "none",
|
|
358
|
+
border: `1px solid ${colors.border}`,
|
|
359
|
+
borderRadius: 10,
|
|
360
|
+
padding: "8px 12px",
|
|
361
|
+
fontSize: 14,
|
|
362
|
+
lineHeight: 1.5,
|
|
363
|
+
background: colors.inputBg,
|
|
364
|
+
color: colors.text,
|
|
365
|
+
outline: "none",
|
|
366
|
+
fontFamily: "inherit",
|
|
367
|
+
maxHeight: 100,
|
|
368
|
+
overflowY: "auto"
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
),
|
|
372
|
+
/* @__PURE__ */ jsx(
|
|
373
|
+
"button",
|
|
374
|
+
{
|
|
375
|
+
onClick: sendMessage,
|
|
376
|
+
disabled: !input.trim() || isTyping,
|
|
377
|
+
style: {
|
|
378
|
+
width: 38,
|
|
379
|
+
height: 38,
|
|
380
|
+
borderRadius: 10,
|
|
381
|
+
background: primaryColor,
|
|
382
|
+
border: "none",
|
|
383
|
+
cursor: "pointer",
|
|
384
|
+
display: "flex",
|
|
385
|
+
alignItems: "center",
|
|
386
|
+
justifyContent: "center",
|
|
387
|
+
color: "#ffffff",
|
|
388
|
+
opacity: !input.trim() || isTyping ? 0.4 : 1,
|
|
389
|
+
flexShrink: 0,
|
|
390
|
+
transition: "opacity 0.15s"
|
|
391
|
+
},
|
|
392
|
+
children: /* @__PURE__ */ jsx(SendIcon, {})
|
|
393
|
+
}
|
|
394
|
+
)
|
|
395
|
+
]
|
|
396
|
+
}
|
|
397
|
+
)
|
|
398
|
+
]
|
|
399
|
+
}
|
|
400
|
+
),
|
|
401
|
+
/* @__PURE__ */ jsx(
|
|
402
|
+
"button",
|
|
403
|
+
{
|
|
404
|
+
onClick: () => setOpen((prev) => !prev),
|
|
405
|
+
style: {
|
|
406
|
+
position: "fixed",
|
|
407
|
+
bottom: 24,
|
|
408
|
+
right: 24,
|
|
409
|
+
width: 56,
|
|
410
|
+
height: 56,
|
|
411
|
+
borderRadius: "50%",
|
|
412
|
+
background: primaryColor,
|
|
413
|
+
border: "none",
|
|
414
|
+
cursor: "pointer",
|
|
415
|
+
display: "flex",
|
|
416
|
+
alignItems: "center",
|
|
417
|
+
justifyContent: "center",
|
|
418
|
+
color: "#ffffff",
|
|
419
|
+
boxShadow: "0 4px 20px rgba(0,0,0,0.2)",
|
|
420
|
+
zIndex: 9999,
|
|
421
|
+
transition: "transform 0.15s, box-shadow 0.15s"
|
|
422
|
+
},
|
|
423
|
+
onMouseEnter: (e) => {
|
|
424
|
+
e.currentTarget.style.transform = "scale(1.08)";
|
|
425
|
+
e.currentTarget.style.boxShadow = "0 6px 24px rgba(0,0,0,0.28)";
|
|
426
|
+
},
|
|
427
|
+
onMouseLeave: (e) => {
|
|
428
|
+
e.currentTarget.style.transform = "scale(1)";
|
|
429
|
+
e.currentTarget.style.boxShadow = "0 4px 20px rgba(0,0,0,0.2)";
|
|
430
|
+
},
|
|
431
|
+
"aria-label": open ? "Close support chat" : "Open support chat",
|
|
432
|
+
children: open ? /* @__PURE__ */ jsx(CloseIcon, { size: 22 }) : /* @__PURE__ */ jsx(ChatIcon, { size: 24 })
|
|
433
|
+
}
|
|
434
|
+
)
|
|
435
|
+
] });
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// src/useClaudeSupport.tsx
|
|
439
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
440
|
+
function useClaudeSupport(options) {
|
|
441
|
+
const { endpoint, knowledge, branding = {} } = options;
|
|
442
|
+
const SupportWidget = () => /* @__PURE__ */ jsx2(
|
|
443
|
+
SupportWidgetComponent,
|
|
444
|
+
{
|
|
445
|
+
endpoint,
|
|
446
|
+
knowledge,
|
|
447
|
+
branding
|
|
448
|
+
}
|
|
449
|
+
);
|
|
450
|
+
SupportWidget.displayName = "ClaudeSupport.Widget";
|
|
451
|
+
return { SupportWidget };
|
|
452
|
+
}
|
|
453
|
+
export {
|
|
454
|
+
useClaudeSupport
|
|
455
|
+
};
|
|
456
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/SupportWidget.tsx","../src/useClaudeSupport.tsx"],"sourcesContent":["\"use client\"\n\nimport React, { useState, useRef, useEffect, useCallback } from \"react\"\nimport type { ClaudeSupport } from \"./useClaudeSupport\"\n\n// ─── Claude logo ──────────────────────────────────────────────────────────────\n\nconst CLAUDE_LOGO =\n \"data:image/svg+xml;base64,\" +\n btoa(\n `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 48 48\" fill=\"none\">\n <rect width=\"48\" height=\"48\" rx=\"12\" fill=\"#D97757\"/>\n <path d=\"M32.16 13H28.7l-7.4 21.82h3.22l1.68-5.18h7.56l1.68 5.18h3.32L32.16 13zm-5.06 13.94 2.96-9.12 2.96 9.12h-5.92zM18.3 13h-3.46L11 22.06 7.16 13H3.7l5.96 13.44L3.7 39h3.46l4.62-10.5L16.4 39h3.46l-6-12.56L18.3 13z\" fill=\"white\"/>\n</svg>`\n )\n\n// ─── Icons ────────────────────────────────────────────────────────────────────\n\nfunction ChatIcon({ size = 24 }: { size?: number }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M12 2C6.477 2 2 6.477 2 12c0 1.89.525 3.66 1.438 5.168L2.546 21.16a.5.5 0 00.628.628l3.992-.892A9.96 9.96 0 0012 22c5.523 0 10-4.477 10-10S17.523 2 12 2z\" />\n </svg>\n )\n}\n\nfunction CloseIcon({ size = 18 }: { size?: number }) {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n )\n}\n\nfunction SendIcon({ size = 18 }: { size?: number }) {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\" />\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\" />\n </svg>\n )\n}\n\n// ─── Typing indicator ─────────────────────────────────────────────────────────\n\nfunction TypingIndicator({ bg }: { bg: string }) {\n return (\n <div\n style={{\n display: \"flex\",\n gap: 4,\n padding: \"10px 14px\",\n background: bg,\n borderRadius: \"18px 18px 18px 4px\",\n width: \"fit-content\",\n alignItems: \"center\",\n }}\n >\n {[0, 1, 2].map((i) => (\n <span\n key={i}\n style={{\n width: 7,\n height: 7,\n borderRadius: \"50%\",\n background: \"#9ca3af\",\n display: \"inline-block\",\n animation: \"bounce 1.2s infinite\",\n animationDelay: `${i * 0.2}s`,\n }}\n />\n ))}\n </div>\n )\n}\n\n// ─── Theme resolver ───────────────────────────────────────────────────────────\n\nfunction useResolvedTheme(theme: ClaudeSupport.Theme): \"light\" | \"dark\" {\n const [resolved, setResolved] = useState<\"light\" | \"dark\">(\"light\")\n\n useEffect(() => {\n if (theme === \"light\" || theme === \"dark\") {\n setResolved(theme)\n return\n }\n\n const checkTheme = () => {\n const html = document.documentElement\n const dataTheme = html.getAttribute(\"data-theme\")\n const classList = html.classList\n\n if (dataTheme === \"dark\" || classList.contains(\"dark\")) {\n setResolved(\"dark\")\n return\n }\n if (dataTheme === \"light\" || classList.contains(\"light\")) {\n setResolved(\"light\")\n return\n }\n\n const prefersDark = window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n setResolved(prefersDark ? \"dark\" : \"light\")\n }\n\n checkTheme()\n\n const observer = new MutationObserver(checkTheme)\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"class\", \"data-theme\", \"style\"],\n })\n\n const mq = window.matchMedia(\"(prefers-color-scheme: dark)\")\n mq.addEventListener(\"change\", checkTheme)\n\n return () => {\n observer.disconnect()\n mq.removeEventListener(\"change\", checkTheme)\n }\n }, [theme])\n\n return resolved\n}\n\n// ─── Widget ───────────────────────────────────────────────────────────────────\n\ninterface SupportWidgetProps {\n endpoint: string\n knowledge: string\n branding: ClaudeSupport.Branding\n}\n\nexport function SupportWidgetComponent({\n endpoint,\n knowledge,\n branding,\n}: SupportWidgetProps) {\n const {\n theme = \"system\",\n primaryColor = \"#D97757\",\n logo = CLAUDE_LOGO,\n title = \"Claude Support\",\n } = branding\n\n const resolvedTheme = useResolvedTheme(theme)\n const isDark = resolvedTheme === \"dark\"\n\n const colors = {\n bg: isDark ? \"#1a1a1a\" : \"#ffffff\",\n border: isDark ? \"#333333\" : \"#e5e7eb\",\n text: isDark ? \"#f1f1f1\" : \"#111111\",\n textMuted: isDark ? \"#9ca3af\" : \"#6b7280\",\n inputBg: isDark ? \"#2a2a2a\" : \"#ffffff\",\n assistantBubble: isDark ? \"#2a2a2a\" : \"#f3f4f6\",\n assistantText: isDark ? \"#f1f1f1\" : \"#111111\",\n }\n\n const [open, setOpen] = useState(false)\n const [messages, setMessages] = useState<ClaudeSupport.Message[]>([])\n const [input, setInput] = useState(\"\")\n const [isTyping, setIsTyping] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const messagesEndRef = useRef<HTMLDivElement>(null)\n const inputRef = useRef<HTMLTextAreaElement>(null)\n\n useEffect(() => {\n messagesEndRef.current?.scrollIntoView({ behavior: \"smooth\" })\n }, [messages, isTyping])\n\n useEffect(() => {\n if (open) setTimeout(() => inputRef.current?.focus(), 100)\n }, [open])\n\n useEffect(() => {\n const handler = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") setOpen(false)\n }\n document.addEventListener(\"keydown\", handler)\n return () => document.removeEventListener(\"keydown\", handler)\n }, [])\n\n const sendMessage = useCallback(async () => {\n if (!input.trim() || isTyping) return\n setError(null)\n\n const userMessage: ClaudeSupport.Message = {\n id: crypto.randomUUID(),\n role: \"user\",\n content: input.trim(),\n timestamp: Date.now(),\n }\n\n const history = messages.map((m) => ({ role: m.role, content: m.content }))\n setMessages((prev) => [...prev, userMessage])\n setInput(\"\")\n setIsTyping(true)\n\n try {\n const res = await fetch(endpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ message: userMessage.content, history, knowledge }),\n })\n\n if (!res.ok) throw new Error(`Request failed: ${res.status}`)\n const data = await res.json()\n\n const assistantMessage: ClaudeSupport.Message = {\n id: crypto.randomUUID(),\n role: \"assistant\",\n content: data.reply,\n timestamp: Date.now(),\n }\n\n setMessages((prev) => [...prev, assistantMessage])\n } catch {\n setError(\"Something went wrong. Please try again.\")\n } finally {\n setIsTyping(false)\n }\n }, [input, isTyping, messages, endpoint, knowledge])\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault()\n sendMessage()\n }\n }\n\n return (\n <>\n <style>{`\n @keyframes bounce {\n 0%, 60%, 100% { transform: translateY(0); }\n 30% { transform: translateY(-6px); }\n }\n @keyframes fadeIn {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n }\n `}</style>\n\n {open && (\n <div\n style={{\n position: \"fixed\",\n bottom: 90,\n right: 24,\n width: 360,\n maxWidth: \"calc(100vw - 32px)\",\n height: 520,\n maxHeight: \"calc(100vh - 120px)\",\n background: colors.bg,\n border: `1px solid ${colors.border}`,\n borderRadius: 16,\n boxShadow: \"0 8px 40px rgba(0,0,0,0.18)\",\n display: \"flex\",\n flexDirection: \"column\",\n zIndex: 9998,\n animation: \"fadeIn 0.2s ease\",\n overflow: \"hidden\",\n }}\n >\n {/* Header */}\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 10,\n padding: \"14px 16px\",\n borderBottom: `1px solid ${colors.border}`,\n background: colors.bg,\n }}\n >\n <img\n src={logo}\n alt=\"logo\"\n style={{ width: 28, height: 28, borderRadius: 6, objectFit: \"cover\" }}\n />\n <span style={{ fontWeight: 600, fontSize: 15, color: colors.text, flex: 1 }}>\n {title}\n </span>\n <button\n onClick={() => setOpen(false)}\n style={{\n background: \"none\",\n border: \"none\",\n cursor: \"pointer\",\n color: colors.textMuted,\n padding: 4,\n display: \"flex\",\n alignItems: \"center\",\n }}\n >\n <CloseIcon />\n </button>\n </div>\n\n {/* Messages */}\n <div\n style={{\n flex: 1,\n overflowY: \"auto\",\n padding: 16,\n display: \"flex\",\n flexDirection: \"column\",\n gap: 12,\n }}\n >\n {messages.length === 0 && (\n <div\n style={{\n background: colors.assistantBubble,\n color: colors.assistantText,\n padding: \"10px 14px\",\n borderRadius: \"18px 18px 18px 4px\",\n fontSize: 14,\n lineHeight: 1.5,\n maxWidth: \"85%\",\n }}\n >\n 👋 Hi! How can I help you today?\n </div>\n )}\n\n {messages.map((msg) => (\n <div\n key={msg.id}\n style={{\n display: \"flex\",\n justifyContent: msg.role === \"user\" ? \"flex-end\" : \"flex-start\",\n }}\n >\n <div\n style={{\n maxWidth: \"85%\",\n padding: \"10px 14px\",\n borderRadius:\n msg.role === \"user\"\n ? \"18px 18px 4px 18px\"\n : \"18px 18px 18px 4px\",\n background:\n msg.role === \"user\" ? primaryColor : colors.assistantBubble,\n color: msg.role === \"user\" ? \"#ffffff\" : colors.assistantText,\n fontSize: 14,\n lineHeight: 1.6,\n wordBreak: \"break-word\",\n whiteSpace: \"pre-wrap\",\n }}\n >\n {msg.content}\n </div>\n </div>\n ))}\n\n {isTyping && <TypingIndicator bg={colors.assistantBubble} />}\n\n {error && (\n <p style={{ fontSize: 12, color: \"#ef4444\", textAlign: \"center\", margin: 0 }}>\n {error}\n </p>\n )}\n\n <div ref={messagesEndRef} />\n </div>\n\n {/* Input */}\n <div\n style={{\n padding: \"10px 12px\",\n borderTop: `1px solid ${colors.border}`,\n display: \"flex\",\n gap: 8,\n alignItems: \"flex-end\",\n background: colors.bg,\n }}\n >\n <textarea\n ref={inputRef}\n value={input}\n onChange={(e) => setInput(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"Ask a question...\"\n rows={1}\n disabled={isTyping}\n style={{\n flex: 1,\n resize: \"none\",\n border: `1px solid ${colors.border}`,\n borderRadius: 10,\n padding: \"8px 12px\",\n fontSize: 14,\n lineHeight: 1.5,\n background: colors.inputBg,\n color: colors.text,\n outline: \"none\",\n fontFamily: \"inherit\",\n maxHeight: 100,\n overflowY: \"auto\",\n }}\n />\n <button\n onClick={sendMessage}\n disabled={!input.trim() || isTyping}\n style={{\n width: 38,\n height: 38,\n borderRadius: 10,\n background: primaryColor,\n border: \"none\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n color: \"#ffffff\",\n opacity: !input.trim() || isTyping ? 0.4 : 1,\n flexShrink: 0,\n transition: \"opacity 0.15s\",\n }}\n >\n <SendIcon />\n </button>\n </div>\n </div>\n )}\n\n {/* Trigger button */}\n <button\n onClick={() => setOpen((prev) => !prev)}\n style={{\n position: \"fixed\",\n bottom: 24,\n right: 24,\n width: 56,\n height: 56,\n borderRadius: \"50%\",\n background: primaryColor,\n border: \"none\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n color: \"#ffffff\",\n boxShadow: \"0 4px 20px rgba(0,0,0,0.2)\",\n zIndex: 9999,\n transition: \"transform 0.15s, box-shadow 0.15s\",\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.transform = \"scale(1.08)\"\n e.currentTarget.style.boxShadow = \"0 6px 24px rgba(0,0,0,0.28)\"\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.transform = \"scale(1)\"\n e.currentTarget.style.boxShadow = \"0 4px 20px rgba(0,0,0,0.2)\"\n }}\n aria-label={open ? \"Close support chat\" : \"Open support chat\"}\n >\n {open ? <CloseIcon size={22} /> : <ChatIcon size={24} />}\n </button>\n </>\n )\n}","\"use client\"\n\nimport React from \"react\"\nimport { SupportWidgetComponent } from \"./SupportWidget\"\n\n// ─── Namespace ────────────────────────────────────────────────────────────────\n\nexport namespace ClaudeSupport {\n export type Theme = \"light\" | \"dark\" | \"system\"\n\n export interface Branding {\n theme?: Theme\n primaryColor?: string\n logo?: string\n title?: string\n }\n\n export interface Message {\n id: string\n role: \"user\" | \"assistant\"\n content: string\n timestamp: number\n }\n\n export interface Options {\n endpoint: string\n knowledge: string\n branding?: Branding\n }\n\n export interface Return {\n SupportWidget: React.FC\n }\n}\n\n// ─── Hook ─────────────────────────────────────────────────────────────────────\n\nexport function useClaudeSupport(options: ClaudeSupport.Options): ClaudeSupport.Return {\n const { endpoint, knowledge, branding = {} } = options\n\n const SupportWidget: React.FC = () => (\n <SupportWidgetComponent\n endpoint={endpoint}\n knowledge={knowledge}\n branding={branding}\n />\n )\n\n SupportWidget.displayName = \"ClaudeSupport.Widget\"\n\n return { SupportWidget }\n}"],"mappings":"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","names":["jsx"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hookraft/use-claude-support",
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"description": "Add an AI-powered support chat to any React or Next.js app in minutes. Powered by Claude.",
|
|
5
|
+
"author": "virus",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "./dist/index.js",
|
|
9
|
+
"module": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"require": "./dist/index.cjs"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsup",
|
|
23
|
+
"dev": "tsup --watch",
|
|
24
|
+
"typecheck": "tsc --noEmit",
|
|
25
|
+
"pub:release": "npm publish --access public"
|
|
26
|
+
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"react": ">=18.0.0",
|
|
29
|
+
"react-dom": ">=18.0.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/react": "^19.2.14",
|
|
33
|
+
"@types/react-dom": "^19.2.3",
|
|
34
|
+
"react": "^19.2.4",
|
|
35
|
+
"react-dom": "^19.2.4",
|
|
36
|
+
"tsup": "^8.5.1",
|
|
37
|
+
"typescript": "^5.9.3"
|
|
38
|
+
},
|
|
39
|
+
"keywords": [
|
|
40
|
+
"react",
|
|
41
|
+
"hooks",
|
|
42
|
+
"claude",
|
|
43
|
+
"ai",
|
|
44
|
+
"support",
|
|
45
|
+
"chat",
|
|
46
|
+
"widget",
|
|
47
|
+
"anthropic",
|
|
48
|
+
"customer-support",
|
|
49
|
+
"nextjs",
|
|
50
|
+
"typescript"
|
|
51
|
+
],
|
|
52
|
+
"repository": {
|
|
53
|
+
"type": "git",
|
|
54
|
+
"url": "https://github.com/purposewalks9/Hookraft"
|
|
55
|
+
},
|
|
56
|
+
"homepage": "https://hookraft.site"
|
|
57
|
+
}
|