@walkspan/chatbot 0.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.
package/dist/index.js ADDED
@@ -0,0 +1,149 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+
19
+ // src/index.js
20
+ var index_exports = {};
21
+ __export(index_exports, {
22
+ FloatingChatbot: () => chatbot_default,
23
+ default: () => index_default
24
+ });
25
+ module.exports = __toCommonJS(index_exports);
26
+
27
+ // src/chatbot.jsx
28
+ var import_react = require("react");
29
+ var import_fa = require("react-icons/fa");
30
+ var FloatingChatbot = ({
31
+ apiUrl,
32
+ position = "bottom-right",
33
+ title = "AI Assistant",
34
+ placeholder = "Ask something..."
35
+ }) => {
36
+ const [open, setOpen] = (0, import_react.useState)(false);
37
+ const [messages, setMessages] = (0, import_react.useState)([]);
38
+ const [inputMessage, setInputMessage] = (0, import_react.useState)("");
39
+ const [isLoading, setIsLoading] = (0, import_react.useState)(false);
40
+ const messagesEndRef = (0, import_react.useRef)(null);
41
+ (0, import_react.useEffect)(() => {
42
+ var _a;
43
+ (_a = messagesEndRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth" });
44
+ }, [messages, isLoading]);
45
+ const positionClasses = {
46
+ "bottom-right": "bottom-6 right-6",
47
+ "bottom-left": "bottom-6 left-6"
48
+ };
49
+ const sendMessage = async () => {
50
+ if (!inputMessage.trim() || isLoading) return;
51
+ const userMessage = {
52
+ id: Date.now(),
53
+ type: "user",
54
+ message: inputMessage
55
+ };
56
+ setMessages((prev) => [...prev, userMessage]);
57
+ setIsLoading(true);
58
+ try {
59
+ const res = await fetch(apiUrl, {
60
+ method: "POST",
61
+ headers: {
62
+ "Content-Type": "application/json"
63
+ },
64
+ body: JSON.stringify({ text: inputMessage.trim() })
65
+ });
66
+ if (!res.ok) throw new Error("API error");
67
+ const data = await res.json();
68
+ setMessages((prev) => [
69
+ ...prev,
70
+ {
71
+ id: Date.now() + 1,
72
+ type: "assistant",
73
+ message: (data == null ? void 0 : data.message) || "No response",
74
+ link: (data == null ? void 0 : data.link) || null
75
+ }
76
+ ]);
77
+ } catch (err) {
78
+ setMessages((prev) => [
79
+ ...prev,
80
+ {
81
+ id: Date.now() + 1,
82
+ type: "assistant",
83
+ message: "Something went wrong. Please try again.",
84
+ isError: true
85
+ }
86
+ ]);
87
+ } finally {
88
+ setIsLoading(false);
89
+ setInputMessage("");
90
+ }
91
+ };
92
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
93
+ "button",
94
+ {
95
+ onClick: () => setOpen(true),
96
+ className: `fixed z-50 ${positionClasses[position]} w-14 h-14 rounded-full bg-[#f1592a] text-white shadow-lg flex items-center justify-center`
97
+ },
98
+ /* @__PURE__ */ React.createElement(import_fa.FaComments, { size: 22 })
99
+ ), open && /* @__PURE__ */ React.createElement(
100
+ "div",
101
+ {
102
+ className: `fixed z-50 ${positionClasses[position]} w-96 max-w-[90vw] h-[500px] bg-white rounded-xl shadow-xl flex flex-col`
103
+ },
104
+ /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between p-4 border-b bg-[#f1592a] text-white rounded-t-xl" }, /* @__PURE__ */ React.createElement("div", { className: "font-medium" }, title), /* @__PURE__ */ React.createElement("button", { onClick: () => setOpen(false) }, /* @__PURE__ */ React.createElement(import_fa.FaTimes, null))),
105
+ /* @__PURE__ */ React.createElement("div", { className: "flex-1 p-4 overflow-y-auto space-y-2" }, messages.map((m) => /* @__PURE__ */ React.createElement(
106
+ "div",
107
+ {
108
+ key: m.id,
109
+ className: `max-w-[80%] py-2 px-5 rounded-3xl text-sm ${m.type === "user" ? "ml-auto bg-[#edf0f6] text-black" : "bg-[#f1592a] text-white"}`
110
+ },
111
+ m == null ? void 0 : m.message,
112
+ m.type !== "user" && m.link && /* @__PURE__ */ React.createElement(
113
+ "a",
114
+ {
115
+ href: m.link,
116
+ target: "_blank",
117
+ rel: "noopener noreferrer",
118
+ className: "block mt-2 underline text-white"
119
+ },
120
+ m.link
121
+ )
122
+ )), isLoading && /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2 text-gray-400" }, /* @__PURE__ */ React.createElement(import_fa.FaRobot, null), " Typing..."), /* @__PURE__ */ React.createElement("div", { ref: messagesEndRef })),
123
+ /* @__PURE__ */ React.createElement("div", { className: "p-3 border-t" }, /* @__PURE__ */ React.createElement("div", { className: "flex gap-2 border rounded-full p-2" }, /* @__PURE__ */ React.createElement(
124
+ "input",
125
+ {
126
+ value: inputMessage,
127
+ onChange: (e) => setInputMessage(e.target.value),
128
+ placeholder,
129
+ className: "flex-1 outline-none focus:ring-0 text-sm",
130
+ onKeyDown: (e) => e.key === "Enter" && sendMessage()
131
+ }
132
+ ), /* @__PURE__ */ React.createElement(
133
+ "button",
134
+ {
135
+ onClick: sendMessage,
136
+ className: "px-3"
137
+ },
138
+ /* @__PURE__ */ React.createElement(import_fa.FaPaperPlane, { color: "#f1592a" })
139
+ )))
140
+ ));
141
+ };
142
+ var chatbot_default = FloatingChatbot;
143
+
144
+ // src/index.js
145
+ var index_default = chatbot_default;
146
+ // Annotate the CommonJS export names for ESM import in node:
147
+ 0 && (module.exports = {
148
+ FloatingChatbot
149
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,123 @@
1
+ // src/chatbot.jsx
2
+ import { useState, useRef, useEffect } from "react";
3
+ import { FaPaperPlane, FaRobot, FaComments, FaTimes } from "react-icons/fa";
4
+ var FloatingChatbot = ({
5
+ apiUrl,
6
+ position = "bottom-right",
7
+ title = "AI Assistant",
8
+ placeholder = "Ask something..."
9
+ }) => {
10
+ const [open, setOpen] = useState(false);
11
+ const [messages, setMessages] = useState([]);
12
+ const [inputMessage, setInputMessage] = useState("");
13
+ const [isLoading, setIsLoading] = useState(false);
14
+ const messagesEndRef = useRef(null);
15
+ useEffect(() => {
16
+ var _a;
17
+ (_a = messagesEndRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth" });
18
+ }, [messages, isLoading]);
19
+ const positionClasses = {
20
+ "bottom-right": "bottom-6 right-6",
21
+ "bottom-left": "bottom-6 left-6"
22
+ };
23
+ const sendMessage = async () => {
24
+ if (!inputMessage.trim() || isLoading) return;
25
+ const userMessage = {
26
+ id: Date.now(),
27
+ type: "user",
28
+ message: inputMessage
29
+ };
30
+ setMessages((prev) => [...prev, userMessage]);
31
+ setIsLoading(true);
32
+ try {
33
+ const res = await fetch(apiUrl, {
34
+ method: "POST",
35
+ headers: {
36
+ "Content-Type": "application/json"
37
+ },
38
+ body: JSON.stringify({ text: inputMessage.trim() })
39
+ });
40
+ if (!res.ok) throw new Error("API error");
41
+ const data = await res.json();
42
+ setMessages((prev) => [
43
+ ...prev,
44
+ {
45
+ id: Date.now() + 1,
46
+ type: "assistant",
47
+ message: (data == null ? void 0 : data.message) || "No response",
48
+ link: (data == null ? void 0 : data.link) || null
49
+ }
50
+ ]);
51
+ } catch (err) {
52
+ setMessages((prev) => [
53
+ ...prev,
54
+ {
55
+ id: Date.now() + 1,
56
+ type: "assistant",
57
+ message: "Something went wrong. Please try again.",
58
+ isError: true
59
+ }
60
+ ]);
61
+ } finally {
62
+ setIsLoading(false);
63
+ setInputMessage("");
64
+ }
65
+ };
66
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
67
+ "button",
68
+ {
69
+ onClick: () => setOpen(true),
70
+ className: `fixed z-50 ${positionClasses[position]} w-14 h-14 rounded-full bg-[#f1592a] text-white shadow-lg flex items-center justify-center`
71
+ },
72
+ /* @__PURE__ */ React.createElement(FaComments, { size: 22 })
73
+ ), open && /* @__PURE__ */ React.createElement(
74
+ "div",
75
+ {
76
+ className: `fixed z-50 ${positionClasses[position]} w-96 max-w-[90vw] h-[500px] bg-white rounded-xl shadow-xl flex flex-col`
77
+ },
78
+ /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between p-4 border-b bg-[#f1592a] text-white rounded-t-xl" }, /* @__PURE__ */ React.createElement("div", { className: "font-medium" }, title), /* @__PURE__ */ React.createElement("button", { onClick: () => setOpen(false) }, /* @__PURE__ */ React.createElement(FaTimes, null))),
79
+ /* @__PURE__ */ React.createElement("div", { className: "flex-1 p-4 overflow-y-auto space-y-2" }, messages.map((m) => /* @__PURE__ */ React.createElement(
80
+ "div",
81
+ {
82
+ key: m.id,
83
+ className: `max-w-[80%] py-2 px-5 rounded-3xl text-sm ${m.type === "user" ? "ml-auto bg-[#edf0f6] text-black" : "bg-[#f1592a] text-white"}`
84
+ },
85
+ m == null ? void 0 : m.message,
86
+ m.type !== "user" && m.link && /* @__PURE__ */ React.createElement(
87
+ "a",
88
+ {
89
+ href: m.link,
90
+ target: "_blank",
91
+ rel: "noopener noreferrer",
92
+ className: "block mt-2 underline text-white"
93
+ },
94
+ m.link
95
+ )
96
+ )), isLoading && /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2 text-gray-400" }, /* @__PURE__ */ React.createElement(FaRobot, null), " Typing..."), /* @__PURE__ */ React.createElement("div", { ref: messagesEndRef })),
97
+ /* @__PURE__ */ React.createElement("div", { className: "p-3 border-t" }, /* @__PURE__ */ React.createElement("div", { className: "flex gap-2 border rounded-full p-2" }, /* @__PURE__ */ React.createElement(
98
+ "input",
99
+ {
100
+ value: inputMessage,
101
+ onChange: (e) => setInputMessage(e.target.value),
102
+ placeholder,
103
+ className: "flex-1 outline-none focus:ring-0 text-sm",
104
+ onKeyDown: (e) => e.key === "Enter" && sendMessage()
105
+ }
106
+ ), /* @__PURE__ */ React.createElement(
107
+ "button",
108
+ {
109
+ onClick: sendMessage,
110
+ className: "px-3"
111
+ },
112
+ /* @__PURE__ */ React.createElement(FaPaperPlane, { color: "#f1592a" })
113
+ )))
114
+ ));
115
+ };
116
+ var chatbot_default = FloatingChatbot;
117
+
118
+ // src/index.js
119
+ var index_default = chatbot_default;
120
+ export {
121
+ chatbot_default as FloatingChatbot,
122
+ index_default as default
123
+ };
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@walkspan/chatbot",
3
+ "version": "0.1.0",
4
+ "main": "dist/index.js",
5
+ "module": "dist/index.mjs",
6
+ "files": [
7
+ "dist"
8
+ ],
9
+ "scripts": {
10
+ "test": "echo \"Error: no test specified\" && exit 1",
11
+ "build": "tsup"
12
+ },
13
+ "keywords": [],
14
+ "author": "Walkspan",
15
+ "license": "MIT",
16
+ "description": "",
17
+ "peerDependencies": {
18
+ "react": ">=17",
19
+ "react-dom": ">=17",
20
+ "react-icons": ">=4",
21
+ "tailwindcss": ">=3"
22
+ },
23
+ "devDependencies": {
24
+ "tsup": "^8.5.1",
25
+ "typescript": "^5.9.3"
26
+ }
27
+ }