aspirechat
Version:
A highly customizable React chatbot component with extensive configuration options
525 lines (504 loc) • 27.3 kB
JavaScript
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
import { useState, useRef, useEffect, useCallback, createContext, useContext } from 'react';
import { v4 } from 'uuid';
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise, SuppressedError, Symbol */
var __assign = function() {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
function __generator(thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
}
function __spreadArray(to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
}
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
function useChat(options) {
var _a;
if (options === void 0) { options = {}; }
var _b = options.initialMessages, initialMessages = _b === void 0 ? [] : _b, persistKey = options.persistKey, _c = options.flows, flows = _c === void 0 ? {} : _c, _d = options.initialFlow, initialFlow = _d === void 0 ? null : _d, _e = options.typingDelay, typingDelay = _e === void 0 ? 1000 : _e, _f = options.initiallyOpen, initiallyOpen = _f === void 0 ? false : _f;
var _g = useState({
messages: initialMessages,
isTyping: false,
isOpen: initiallyOpen,
isMinimized: false,
currentFlow: initialFlow,
availableOptions: (initialFlow && ((_a = flows[initialFlow]) === null || _a === void 0 ? void 0 : _a.options)) || [],
}), state = _g[0], setState = _g[1];
// Track if component is mounted
var isMounted = useRef(true);
useEffect(function () {
return function () {
isMounted.current = false;
};
}, []);
// Load persisted messages if available
useEffect(function () {
if (persistKey) {
try {
var savedMessages_1 = localStorage.getItem(persistKey);
if (savedMessages_1) {
setState(function (prev) { return (__assign(__assign({}, prev), { messages: JSON.parse(savedMessages_1) })); });
}
}
catch (error) {
console.error("Error loading persisted chat messages:", error);
}
}
}, [persistKey]);
// Save messages to localStorage when they change
useEffect(function () {
if (persistKey && state.messages.length > 0) {
try {
localStorage.setItem(persistKey, JSON.stringify(state.messages));
}
catch (error) {
console.error("Error persisting chat messages:", error);
}
}
}, [state.messages, persistKey]);
// Initialize first flow if provided
useEffect(function () {
if (initialFlow && flows[initialFlow] && state.messages.length === 0) {
startFlow(initialFlow);
}
}, [initialFlow, flows]);
var addMessage = useCallback(function (message) {
var newMessage = __assign(__assign({}, message), { id: v4(), timestamp: Date.now() });
setState(function (prev) { return (__assign(__assign({}, prev), { messages: __spreadArray(__spreadArray([], prev.messages, true), [newMessage], false) })); });
return newMessage;
}, []);
var updateMessage = useCallback(function (id, updates) {
setState(function (prev) { return (__assign(__assign({}, prev), { messages: prev.messages.map(function (msg) {
return msg.id === id ? __assign(__assign({}, msg), updates) : msg;
}) })); });
}, []);
var clearMessages = useCallback(function () {
setState(function (prev) {
var _a;
return (__assign(__assign({}, prev), { messages: [], availableOptions: prev.currentFlow
? ((_a = flows[prev.currentFlow]) === null || _a === void 0 ? void 0 : _a.options) || []
: [] }));
});
if (persistKey) {
localStorage.removeItem(persistKey);
}
}, [persistKey, flows]);
// Start a specific flow
var startFlow = useCallback(function (flowId) {
var flow = flows[flowId];
if (!flow)
return;
// Show typing indicator
setState(function (prev) { return (__assign(__assign({}, prev), { isTyping: true, currentFlow: flowId })); });
// Add each message in the flow with a delay
var delay = 0;
flow.messages.forEach(function (message) {
setTimeout(function () {
if (isMounted.current) {
addMessage(message);
// After the last message, set available options and turn off typing
if (message === flow.messages[flow.messages.length - 1]) {
setState(function (prev) { return (__assign(__assign({}, prev), { isTyping: false, availableOptions: flow.options || [] })); });
}
}
}, delay);
delay += typingDelay;
});
}, [flows, typingDelay, addMessage]);
// Handle button clicks
var handleButtonClick = useCallback(function (option) {
// Add user's selection as a message
addMessage({
text: option.text,
type: "user",
});
// If there's a next flow, start it
if (option.nextFlow && flows[option.nextFlow]) {
startFlow(option.nextFlow);
}
// Otherwise, just add the button value as a bot response
else if (option.value) {
// Show typing indicator
setState(function (prev) { return (__assign(__assign({}, prev), { isTyping: true, availableOptions: [] })); });
setTimeout(function () {
if (isMounted.current) {
addMessage({
text: option.value,
type: "bot",
});
setState(function (prev) { return (__assign(__assign({}, prev), { isTyping: false })); });
}
}, typingDelay);
}
}, [addMessage, flows, startFlow, typingDelay]);
var toggleChat = useCallback(function () {
setState(function (prev) { return (__assign(__assign({}, prev), { isOpen: !prev.isOpen })); });
}, []);
var openChat = useCallback(function () {
setState(function (prev) { return (__assign(__assign({}, prev), { isOpen: true })); });
}, []);
var closeChat = useCallback(function () {
setState(function (prev) { return (__assign(__assign({}, prev), { isOpen: false })); });
}, []);
// Add controls for minimizing the chat
var minimizeChat = useCallback(function () {
setState(function (prev) { return (__assign(__assign({}, prev), { isMinimized: true })); });
}, []);
var maximizeChat = useCallback(function () {
setState(function (prev) { return (__assign(__assign({}, prev), { isMinimized: false })); });
}, []);
return {
messages: state.messages,
isTyping: state.isTyping,
isOpen: state.isOpen,
isMinimized: state.isMinimized,
availableOptions: state.availableOptions,
currentFlow: state.currentFlow,
addMessage: addMessage,
updateMessage: updateMessage,
clearMessages: clearMessages,
toggleChat: toggleChat,
openChat: openChat,
closeChat: closeChat,
minimizeChat: minimizeChat,
maximizeChat: maximizeChat,
startFlow: startFlow,
handleButtonClick: handleButtonClick,
};
}
var ChatContext = createContext(null);
var ChatContextProvider = function (_a) {
var children = _a.children, _b = _a.initialConfig, initialConfig = _b === void 0 ? {} : _b, _c = _a.initialOptions, initialOptions = _c === void 0 ? {} : _c;
var chat = useChat(__assign({ initialMessages: initialConfig.initialMessages || [], persistKey: initialConfig.persistKey, flows: initialConfig.flows || {}, initialFlow: initialConfig.initialFlow, typingDelay: initialConfig.typingIndicatorTimeout || 1000, initiallyOpen: initialConfig.initiallyOpen || false }, initialOptions));
// We need to implement a proper removeMessage function
var removeMessage = useCallback(function (id) {
// We can use updateMessage to "remove" by filtering out the message in the UI
// Real removal would require modifying the useChat hook
chat.updateMessage(id, { text: "", type: "system" });
}, [chat]);
// Implement setIsTyping to properly change typing state
var setIsTyping = useCallback(function (typing) {
if (typing === chat.isTyping)
return; // No change needed
// Since we don't have direct access to setState in useChat,
// we'll use a workaround for setting typing state
if (typing) {
// Simulate typing start if we need to
var placeholderMsg = {
text: "",
type: "bot",
isTyping: true,
};
// This will trigger the typing indicator indirectly
var tempMsg_1 = chat.addMessage(placeholderMsg);
// Clean up after a delay - this is optional
if (!chat.isTyping) {
setTimeout(function () {
// Remove the temporary typing message or replace it with an empty message
chat.updateMessage(tempMsg_1.id, { text: "", type: "system" });
}, initialConfig.typingIndicatorTimeout || 1000);
}
}
// For turning off typing, we don't need to do anything special
// as the typing indicator is controlled by message state in components
}, [chat, initialConfig.typingIndicatorTimeout]);
// Create a value object that fully matches ChatContextType
var contextValue = {
messages: chat.messages,
isTyping: chat.isTyping,
isOpen: chat.isOpen,
isMinimized: chat.isMinimized,
currentFlow: chat.currentFlow,
availableOptions: chat.availableOptions,
config: initialConfig,
// Methods from useChat
addMessage: chat.addMessage,
updateMessage: chat.updateMessage,
clearMessages: chat.clearMessages,
toggleChat: chat.toggleChat,
openChat: chat.openChat,
closeChat: chat.closeChat,
minimizeChat: chat.minimizeChat,
maximizeChat: chat.maximizeChat,
startFlow: chat.startFlow,
handleButtonClick: chat.handleButtonClick,
// Our custom implementations
removeMessage: removeMessage,
setIsOpen: function (open) {
if (open)
chat.openChat();
else
chat.closeChat();
},
setIsMinimized: function (minimized) {
if (minimized)
chat.minimizeChat();
else
chat.maximizeChat();
},
setIsTyping: setIsTyping,
};
return (jsx(ChatContext.Provider, { value: contextValue, children: children }));
};
var useGlobalChat = function () {
var context = useContext(ChatContext);
if (!context) {
throw new Error("useGlobalChat must be used within a ChatContextProvider");
}
return context;
};
var ChatHeader = function (_a) {
var _b = _a.title, title = _b === void 0 ? "Chat Support" : _b, logo = _a.logo;
var _c = useGlobalChat(), minimizeChat = _c.minimizeChat, closeChat = _c.closeChat, isMinimized = _c.isMinimized, maximizeChat = _c.maximizeChat;
return (jsxs("div", { className: "flex items-center p-3 bg-blue-500 text-white", role: "heading", "aria-level": 1, children: [logo && jsx("img", { src: logo, alt: "Chat Logo", className: "h-6 w-auto mr-2" }), jsx("h3", { className: "text-base font-semibold flex-1", children: title }), jsxs("div", { className: "flex gap-2", children: [isMinimized ? (jsx("button", { onClick: maximizeChat, className: "p-1 hover:bg-blue-600 rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-300", "aria-label": "Maximize chat", children: jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("polyline", { points: "5 12 12 5 19 12" }) }) })) : (jsx("button", { onClick: minimizeChat, className: "p-1 hover:bg-blue-600 rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-300", "aria-label": "Minimize chat", children: jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("polyline", { points: "5 9 12 16 19 9" }) }) })), jsx("button", { onClick: closeChat, className: "p-1 hover:bg-blue-600 rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-300", "aria-label": "Close chat", children: jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }) })] })] }));
};
/**
* Creates a bot response message object
*/
function createChatbotResponse(text, metadata) {
return {
text: text,
type: "bot",
metadata: metadata,
};
}
/**
* Formats a timestamp according to the provided format
*/
function formatTimestamp(timestamp, format) {
if (format === void 0) { format = "HH:mm"; }
var date = new Date(timestamp);
if (format === "HH:mm") {
return "".concat(String(date.getHours()).padStart(2, "0"), ":").concat(String(date.getMinutes()).padStart(2, "0"));
}
if (format === "HH:mm:ss") {
return "".concat(String(date.getHours()).padStart(2, "0"), ":").concat(String(date.getMinutes()).padStart(2, "0"), ":").concat(String(date.getSeconds()).padStart(2, "0"));
}
return date.toLocaleString();
}
var processResponse = function (response, messageText) { return __awaiter(void 0, void 0, void 0, function () {
var result;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!(typeof response === "function")) return [3 /*break*/, 3];
result = response(messageText);
if (!(result instanceof Promise)) return [3 /*break*/, 2];
return [4 /*yield*/, result];
case 1: return [2 /*return*/, _a.sent()];
case 2: return [2 /*return*/, result];
case 3: return [2 /*return*/, response];
}
});
}); };
var ChatMessage = function (_a) {
var message = _a.message;
var isUser = message.type === "user";
return (jsxs("div", { className: "flex flex-col mb-3 max-w-[80%] ".concat(isUser ? "items-end self-end" : "items-start self-start"), role: isUser ? "complementary" : "region", "aria-label": "".concat(isUser ? "User" : "Bot", " message"), children: [jsx("div", { className: "rounded-2xl px-4 py-2 ".concat(isUser ? "bg-blue-500 text-white" : "bg-gray-100 text-gray-800"), children: message.html ? (jsx("div", { dangerouslySetInnerHTML: { __html: message.text }, "aria-live": "polite" })) : (jsx("p", { children: message.text })) }), jsx("div", { className: "text-xs text-gray-400 mt-1", "aria-hidden": "true", children: jsx("time", { dateTime: new Date(message.timestamp).toISOString(), children: formatTimestamp(message.timestamp) }) })] }));
};
var ChatButtons = function (_a) {
var options = _a.options, onButtonClick = _a.onButtonClick;
if (!options || options.length === 0) {
return null;
}
return (jsx("div", { className: "w-full flex flex-wrap gap-2 p-3 border-t border-gray-200", role: "group", "aria-label": "Chat options", children: options.map(function (option) { return (jsx("button", { className: "bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-full text-sm font-medium transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500", onClick: function () { return onButtonClick(option); }, type: "button", "aria-label": option.text, children: option.text }, option.id)); }) }));
};
var ChatInput = function () {
var _a = useGlobalChat(), availableOptions = _a.availableOptions, handleButtonClick = _a.handleButtonClick, isTyping = _a.isTyping;
// Don't show options while typing
if (isTyping) {
return (jsx("div", { className: "border-t border-gray-200 p-4 flex items-center justify-center chat-typing-indicator", "aria-live": "polite", "aria-label": "Bot is typing", children: jsxs("div", { className: "flex space-x-2 items-center", children: [jsx("div", { className: "w-2 h-2 bg-gray-400 rounded-full", style: { animationDelay: "0ms" } }), jsx("div", { className: "w-2 h-2 bg-gray-400 rounded-full", style: { animationDelay: "150ms" } }), jsx("div", { className: "w-2 h-2 bg-gray-400 rounded-full", style: { animationDelay: "300ms" } })] }) }));
}
return (jsx(ChatButtons, { options: availableOptions, onButtonClick: handleButtonClick }));
};
var ChatToggleButton = function (_a) {
var _b = _a.config, config = _b === void 0 ? {} : _b;
var toggleChat = useGlobalChat().toggleChat;
// Style variables based on position
var positionClasses = (function () {
var _a;
var position = ((_a = config === null || config === void 0 ? void 0 : config.position) === null || _a === void 0 ? void 0 : _a.placement) || "bottom-right";
switch (position) {
case "top-left":
return "top-5 left-5";
case "top-right":
return "top-5 right-5";
case "bottom-left":
return "top-5 left-5";
case "bottom-right":
default:
return "bottom-5 right-5";
}
})();
return (jsx("button", { onClick: toggleChat, className: "fixed ".concat(positionClasses, " z-50 w-14 h-14 bg-blue-500 hover:bg-blue-600 text-white rounded-full flex items-center justify-center shadow-lg transition-transform duration-300 ease-in-out hover:scale-105 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"), "aria-label": "Toggle chat", children: jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) }) }));
};
var Chatbot = function (_a) {
var _b = _a.config, config = _b === void 0 ? {} : _b;
// Use the global chat context instead of direct hook
var _c = useGlobalChat(), isOpen = _c.isOpen, isMinimized = _c.isMinimized, messages = _c.messages;
var messagesEndRef = useRef(null);
// Auto scroll to bottom when messages change
useEffect(function () {
if (!config.disableAutoScroll && messagesEndRef.current && !isMinimized) {
messagesEndRef.current.scrollIntoView({ behavior: "smooth" });
}
}, [messages, isMinimized, config.disableAutoScroll]);
if (!isOpen) {
return jsx(ChatToggleButton, { config: config });
}
// Style variables based on position
var positionClasses = (function () {
var _a;
var position = ((_a = config.position) === null || _a === void 0 ? void 0 : _a.placement) || "bottom-right";
switch (position) {
case "top-left":
return "top-5 left-5";
case "top-right":
return "top-5 right-5";
case "bottom-left":
return "bottom-5 left-5";
case "bottom-right":
default:
return "bottom-5 right-5";
}
})();
return (jsxs("div", { className: "fixed ".concat(positionClasses, " z-50 bg-white rounded-lg shadow-xl overflow-hidden flex flex-col aspire-chat-container"), style: {
width: config.width || "350px",
maxWidth: "90vw",
maxHeight: config.maxHeight || "600px",
minHeight: isMinimized ? "60px" : "300px",
}, role: "dialog", "aria-label": "Chat window", children: [jsx(ChatHeader, { title: config.headerTitle, logo: config.logo }), !isMinimized && (jsxs(Fragment, { children: [jsxs("div", { className: "flex-1 overflow-y-auto p-4 flex flex-col gap-3", role: "log", "aria-live": "polite", children: [messages.map(function (message) { return (jsx(ChatMessage, { message: message }, message.id)); }), jsx("div", { ref: messagesEndRef })] }), jsx(ChatInput, {})] }))] }));
};
var defaultTheme = {
// Main colors
primary: "#4F46E5", // Indigo-600
secondary: "#6366F1", // Indigo-500
background: "#FFFFFF",
textPrimary: "#1F2937", // Gray-800
textSecondary: "#4B5563", // Gray-600
// Message bubbles
userBubbleBackground: "#4F46E5", // Indigo-600
userBubbleText: "#FFFFFF",
botBubbleBackground: "#F3F4F6", // Gray-100
botBubbleText: "#1F2937", // Gray-800
systemMessageColor: "#9CA3AF", // Gray-400
// Header
headerBackground: "#4F46E5", // Indigo-600
headerText: "#FFFFFF",
// Input
inputBackground: "#FFFFFF",
inputFieldBackground: "#F9FAFB", // Gray-50
inputTextColor: "#1F2937", // Gray-800
inputBorderColor: "#E5E7EB", // Gray-200
// Misc
borderColor: "#E5E7EB", // Gray-200
timestampColor: "#9CA3AF", // Gray-400
errorColor: "#EF4444", // Red-500
successColor: "#10B981", // Green-500
// Typography
fontFamily: 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif',
fontSize: "14px",
fontSizeSmall: "12px",
fontSizeLarge: "16px",
// Spacing
spacing: {
unit: 4,
tiny: "4px",
small: "8px",
medium: "16px",
large: "24px",
extraLarge: "32px",
},
// Border radius
borderRadius: {
small: "4px",
medium: "8px",
large: "16px",
circle: "50%",
},
// Box shadow
boxShadow: {
light: "0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)",
medium: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)",
heavy: "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)",
},
// Animations
animations: {
transitionDuration: "200ms",
easing: "ease-in-out",
},
};
var darkTheme = __assign(__assign({}, defaultTheme), {
// Main colors
primary: "#6366F1", secondary: "#818CF8", background: "#1F2937", textPrimary: "#F9FAFB", textSecondary: "#E5E7EB",
// Message bubbles
userBubbleBackground: "#6366F1", userBubbleText: "#FFFFFF", botBubbleBackground: "#374151", botBubbleText: "#F9FAFB",
// Header
headerBackground: "#6366F1", headerText: "#FFFFFF",
// Input
inputBackground: "#1F2937", inputFieldBackground: "#374151", inputTextColor: "#F9FAFB", inputBorderColor: "#4B5563",
// Misc
borderColor: "#4B5563", timestampColor: "#9CA3AF" });
export { ChatButtons, ChatContextProvider, ChatHeader, ChatInput, ChatMessage, ChatToggleButton, Chatbot, createChatbotResponse, darkTheme, defaultTheme, formatTimestamp, processResponse, useChat, useGlobalChat };
//# sourceMappingURL=index.esm.js.map