UNPKG

sandia-chatbot-widget

Version:

Production-ready Sandia AI Chatbot Widget v3.0 with advanced themes, animations, notifications, and enterprise features

1,382 lines 78.4 kB
import { jsx } from 'react/jsx-runtime';
import { useRef, useState, useEffect } from 'react';

/******************************************************************************
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, Iterator */


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 = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
    return g.next = verb(0), g["throw"] = verb(1), g["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;
};

var SandiaWidget = function (_a) {
    var _b, _c, _d, _e;
    var chatbotId = _a.chatbotId, shareToken = _a.shareToken, apiUrl = _a.apiUrl, _f = _a.styles, styles = _f === void 0 ? {} : _f, _g = _a.chatConfig, chatConfig = _g === void 0 ? {} : _g, onReady = _a.onReady, onOpen = _a.onOpen, onClose = _a.onClose, onMinimize = _a.onMinimize, onRestore = _a.onRestore, onMessage = _a.onMessage, onTyping = _a.onTyping, onError = _a.onError, onSubscriptionError = _a.onSubscriptionError, onFileUpload = _a.onFileUpload, onVoiceStart = _a.onVoiceStart, onVoiceEnd = _a.onVoiceEnd, metadata = _a.metadata, _h = _a.debug, debug = _h === void 0 ? false : _h, _j = _a.version, version = _j === void 0 ? '3.0' : _j, 
    // Legacy props
    position = _a.position, primaryColor = _a.primaryColor, size = _a.size;
    var initialized = useRef(false);
    var _k = useState(null), subscriptionError = _k[0], setSubscriptionError = _k[1];
    var _l = useState(false), isClient = _l[0], setIsClient = _l[1];
    // Default API URL to Sandia's service
    var finalApiUrl = apiUrl || 'https://www.sandia.chat';
    // Merge legacy props with new styles for backward compatibility
    var mergedStyles = __assign(__assign(__assign(__assign({ 
        // v3.0 defaults
        position: 'bottom-right', primaryColor: '#006FEE', backgroundColor: '#ffffff', textColor: '#000000', borderRadius: 50, size: 'md', theme: 'modern', shadowStyle: 'soft', animation: 'smooth', showPulse: true, showBadge: true, customIcon: '💬', greeting: 'Hi! How can I help you today?', darkMode: false, showAvatar: true, showTimestamps: true, soundEnabled: true, notificationsEnabled: true, allowFileUpload: true, showTypingIndicator: true, messagePersistence: true, maxMessages: 100, autoMinimize: 5, brandingEnabled: true, mobileFullScreen: true }, styles), (position && { position: position })), (primaryColor && { primaryColor: primaryColor })), (size && { size: size }));
    // Enhanced chat configuration with defaults
    var mergedChatConfig = __assign({ quickReplies: ['Hello', 'How can you help?', 'Tell me more'], voiceEnabled: false, voiceLanguage: 'en-US', allowedFileTypes: ['image/*', '.pdf', '.txt', '.doc', '.docx'], maxFileSize: 10, messagesPerMinute: 10, trackingEnabled: true }, chatConfig);
    // Detect client-side rendering
    useEffect(function () {
        setIsClient(true);
    }, []);
    useEffect(function () {
        // Only run on client-side
        if (!isClient || initialized.current)
            return;
        initialized.current = true;
        // Validate access before initializing
        validateAccess();
    }, [chatbotId, finalApiUrl, shareToken, isClient]);
    var validateAccess = function () { return __awaiter(void 0, void 0, void 0, function () {
        var headers, response, error, error_1;
        return __generator(this, function (_b) {
            switch (_b.label) {
                case 0:
                    _b.trys.push([0, 7, , 8]);
                    headers = {
                        'Content-Type': 'application/json'
                    };
                    if (shareToken) {
                        headers['x-share-token'] = shareToken;
                    }
                    // Add version header for API compatibility
                    if (version) {
                        headers['x-widget-version'] = version;
                    }
                    return [4 /*yield*/, fetch("".concat(finalApiUrl, "/api/chatbot/public/").concat(chatbotId, "/config"), {
                            method: 'GET',
                            headers: headers,
                            mode: 'cors', // Explicitly enable CORS
                            credentials: 'omit' // Don't send credentials for public API
                        })];
                case 1:
                    response = _b.sent();
                    if (!!response.ok) return [3 /*break*/, 6];
                    error = void 0;
                    _b.label = 2;
                case 2:
                    _b.trys.push([2, 4, , 5]);
                    return [4 /*yield*/, response.json()];
                case 3:
                    error = _b.sent();
                    return [3 /*break*/, 5];
                case 4:
                    _b.sent();
                    error = { message: 'Network error' };
                    return [3 /*break*/, 5];
                case 5:
                    if (response.status === 402) {
                        // Subscription error
                        setSubscriptionError(error.message || 'This chatbot has reached its usage limits.');
                        if (onSubscriptionError) {
                            onSubscriptionError({
                                message: error.message || 'Subscription limit reached',
                                upgradeRequired: error.upgradeRequired
                            });
                        }
                        return [2 /*return*/];
                    }
                    if (response.status === 403 && !shareToken) {
                        // If access denied and no share token provided, show a helpful error
                        console.warn('[Sandia Widget] Chatbot requires authentication or is not public. Consider providing a shareToken.');
                        setSubscriptionError('This chatbot requires authentication. Please contact the owner for access.');
                        return [2 /*return*/];
                    }
                    throw new Error(error.message || "HTTP ".concat(response.status, ": ").concat(response.statusText));
                case 6:
                    // Access validated, proceed with initialization
                    initializeChatbot();
                    return [3 /*break*/, 8];
                case 7:
                    error_1 = _b.sent();
                    console.error('[Sandia Widget] Access validation failed:', error_1);
                    // Handle CORS and network errors gracefully
                    if (error_1 instanceof TypeError && error_1.message.includes('fetch')) {
                        console.warn('[Sandia Widget] Network error - possibly CORS related. Falling back to basic initialization.');
                        // Try to initialize anyway for development/testing
                        initializeChatbot();
                        return [2 /*return*/];
                    }
                    // For other errors, show user-friendly message
                    setSubscriptionError('Unable to connect to chatbot service. Please try again later.');
                    if (onError) {
                        onError(error_1);
                    }
                    return [3 /*break*/, 8];
                case 8: return [2 /*return*/];
            }
        });
    }); };
    var initializeChatbot = function () {
        // Configure the enhanced global chatbot object with v3.0 features
        window.SandiaChatbot = {
            chatbotId: chatbotId,
            shareToken: shareToken,
            apiUrl: finalApiUrl,
            version: version,
            styles: mergedStyles,
            chatConfig: mergedChatConfig,
            // Enhanced event handlers
            onReady: function () {
                if (debug)
                    console.log('[Sandia Widget v3.0] Chatbot ready');
                if (onReady)
                    onReady();
            },
            onOpen: function () {
                if (debug)
                    console.log('[Sandia Widget v3.0] Chatbot opened');
                if (onOpen)
                    onOpen();
            },
            onClose: function () {
                if (debug)
                    console.log('[Sandia Widget v3.0] Chatbot closed');
                if (onClose)
                    onClose();
            },
            onMinimize: function () {
                if (debug)
                    console.log('[Sandia Widget v3.0] Chatbot minimized');
                if (onMinimize)
                    onMinimize();
            },
            onRestore: function () {
                if (debug)
                    console.log('[Sandia Widget v3.0] Chatbot restored');
                if (onRestore)
                    onRestore();
            },
            onMessage: function (message) {
                var enhancedMessage = __assign(__assign({}, message), { timestamp: message.timestamp || new Date() });
                if (debug)
                    console.log('[Sandia Widget v3.0] Message:', enhancedMessage);
                if (onMessage)
                    onMessage(enhancedMessage);
            },
            onTyping: function (isTyping) {
                if (debug)
                    console.log('[Sandia Widget v3.0] Typing:', isTyping);
                if (onTyping)
                    onTyping(isTyping);
            },
            onError: function (error) {
                if (debug)
                    console.error('[Sandia Widget v3.0] Error:', error);
                if (onError)
                    onError(error);
            },
            onSubscriptionError: function (error) {
                if (debug)
                    console.warn('[Sandia Widget v3.0] Subscription Error:', error);
                if (onSubscriptionError)
                    onSubscriptionError(error);
            },
            onFileUpload: function (file) {
                if (debug)
                    console.log('[Sandia Widget v3.0] File Upload:', file.name);
                if (onFileUpload)
                    onFileUpload(file);
            },
            onVoiceStart: function () {
                if (debug)
                    console.log('[Sandia Widget v3.0] Voice recording started');
                if (onVoiceStart)
                    onVoiceStart();
            },
            onVoiceEnd: function (transcript) {
                if (debug)
                    console.log('[Sandia Widget v3.0] Voice recording ended:', transcript);
                if (onVoiceEnd)
                    onVoiceEnd(transcript);
            },
            metadata: metadata,
            debug: debug,
        };
        // Load the enhanced embed script from Sandia's CDN
        var script = document.createElement('script');
        script.src = "".concat(finalApiUrl, "/embed.js?v=").concat(version);
        script.async = true;
        script.onload = function () {
            if (debug)
                console.log('[Sandia Widget v3.0] Enhanced embed script loaded');
        };
        script.onerror = function (error) {
            console.error('[Sandia Widget v3.0] Failed to load embed script:', error);
            if (onError)
                onError(new Error('Failed to load chatbot'));
        };
        document.head.appendChild(script);
        return function () {
            // Enhanced cleanup
            if (script.parentNode) {
                document.head.removeChild(script);
            }
            delete window.SandiaChatbot;
            // Clear any persistent data if needed
            if (mergedStyles.messagePersistence === false) {
                try {
                    localStorage.removeItem("sandia-chatbot-".concat(chatbotId));
                }
                catch (e) {
                    // Ignore localStorage errors
                }
            }
        };
    };
    // Don't render anything on server-side
    if (!isClient) {
        return null;
    }
    // Enhanced subscription error state with v3.0 styling
    if (subscriptionError) {
        return (jsx("div", { style: {
                position: 'fixed',
                bottom: ((_b = mergedStyles.position) === null || _b === void 0 ? void 0 : _b.includes('bottom')) ? '24px' : 'auto',
                top: ((_c = mergedStyles.position) === null || _c === void 0 ? void 0 : _c.includes('top')) ? '24px' : 'auto',
                right: ((_d = mergedStyles.position) === null || _d === void 0 ? void 0 : _d.includes('right')) ? '24px' : 'auto',
                left: ((_e = mergedStyles.position) === null || _e === void 0 ? void 0 : _e.includes('left')) ? '24px' : 'auto',
                width: '60px',
                height: '60px',
                background: mergedStyles.darkMode ? '#374151' : '#6b7280',
                borderRadius: "".concat(mergedStyles.borderRadius, "%"),
                display: 'flex',
                alignItems: 'center',
                justifyContent: 'center',
                boxShadow: mergedStyles.shadowStyle === 'hard' ? '0 4px 12px rgba(0,0,0,0.3)' :
                    mergedStyles.shadowStyle === 'glow' ? "0 0 20px ".concat(mergedStyles.primaryColor, "40") :
                        mergedStyles.shadowStyle === 'none' ? 'none' :
                            '0 4px 20px rgba(0,0,0,0.15)', // soft shadow (default)
                fontSize: '24px',
                opacity: 0.6,
                cursor: 'not-allowed',
                zIndex: 9999,
                fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
                transition: 'all 0.3s ease',
                animation: mergedStyles.animation === 'bouncy' ? 'pulse 2s infinite' :
                    mergedStyles.animation === 'fade' ? 'fadeIn 0.5s ease' :
                        'none'
            }, children: "\u26A0\uFE0F" }));
    }
    return null; // Widget is handled by the enhanced embed script
};

var DEFAULT_STYLES = {
    position: 'bottom-right',
    primaryColor: '#006FEE',
    backgroundColor: '#ffffff',
    textColor: '#000000',
    borderRadius: 50,
    size: 'md',
    theme: 'modern',
    shadowStyle: 'soft',
    animation: 'smooth',
    showPulse: true,
    showBadge: true,
    customIcon: '💬',
    greeting: 'Hi! How can I help you today?',
    darkMode: false,
    showAvatar: true,
    showTimestamps: true,
    soundEnabled: true,
    notificationsEnabled: true,
    allowFileUpload: true,
    showTypingIndicator: true,
    messagePersistence: true,
    maxMessages: 100,
    autoMinimize: 5,
    brandingEnabled: true,
    mobileFullScreen: true
};
var DEFAULT_CHAT_CONFIG = {
    quickReplies: ['Hello', 'How can you help?', 'Tell me more'],
    voiceEnabled: false,
    voiceLanguage: 'en-US',
    allowedFileTypes: ['image/*', '.pdf', '.txt', '.doc', '.docx'],
    maxFileSize: 10,
    messagesPerMinute: 10,
    trackingEnabled: true
};
var SandiaVanillaChatbot = /** @class */ (function () {
    function SandiaVanillaChatbot(config) {
        this.container = null;
        this.isOpen = false;
        this.isMinimized = false;
        this.messages = [];
        this.isLoading = false;
        this.conversationId = null;
        this.unreadCount = 0;
        this.lastActivity = Date.now();
        this.typingTimeout = null;
        this.autoMinimizeTimeout = null;
        this.notificationPermission = 'default';
        // Sound effects (data URLs for production use)
        this.sounds = {
            messageReceived: 'data:audio/wav;base64,UklGRnoGAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQoGAACBhYqFbF1fdJivrJBhNjVgodDbq2EcBj+a2/LDciUFLIHO8tiJNwgZaLvt559NEAxQp+PwtmMcBjiR1/LMeSwFJHfH8N2QQAoUXrTp66hVFApGn+DyvmwhBT2a3Aw==',
            messageClick: 'data:audio/wav;base64,UklGRnoGAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQoGAACBhYqFbF1fdJivrJBhNjVgodDbq2EcBj+a2/LDciUFLIHO8tiJNwgZaLvt559NEAxQp+PwtmMcBjiR1/LMeSwFJHfH8N2QQAoUXrTp66hVFApGn+DyvmwhBT2Z3Aw=='
        };
        this.chatbotId = config.chatbotId;
        this.shareToken = config.shareToken;
        this.apiUrl = config.apiUrl || 'https://www.sandia.chat';
        this.styles = __assign(__assign({}, DEFAULT_STYLES), config.styles);
        this.chatConfig = __assign(__assign({}, DEFAULT_CHAT_CONFIG), config.chatConfig);
        this.debug = config.debug || false;
        this.version = config.version || '3.0';
        this.metadata = config.metadata;
        // Bind event handlers
        this.onReady = config.onReady;
        this.onOpen = config.onOpen;
        this.onClose = config.onClose;
        this.onMinimize = config.onMinimize;
        this.onRestore = config.onRestore;
        this.onMessage = config.onMessage;
        this.onTyping = config.onTyping;
        this.onError = config.onError;
        this.onSubscriptionError = config.onSubscriptionError;
        this.onFileUpload = config.onFileUpload;
        this.onVoiceStart = config.onVoiceStart;
        this.onVoiceEnd = config.onVoiceEnd;
        this.init();
    }
    SandiaVanillaChatbot.prototype.init = function () {
        return __awaiter(this, void 0, void 0, function () {
            var _a, hasAccess, error_1;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        _b.trys.push([0, 4, , 5]);
                        if (!(this.styles.notificationsEnabled && 'Notification' in window)) return [3 /*break*/, 2];
                        _a = this;
                        return [4 /*yield*/, Notification.requestPermission()];
                    case 1:
                        _a.notificationPermission = _b.sent();
                        _b.label = 2;
                    case 2:
                        // Load message history
                        if (this.styles.messagePersistence) {
                            this.loadMessageHistory();
                        }
                        return [4 /*yield*/, this.validateAccess()];
                    case 3:
                        hasAccess = _b.sent();
                        if (!hasAccess) {
                            this.renderBlockedState();
                            return [2 /*return*/];
                        }
                        // Create widget
                        this.createWidget();
                        this.addEnhancedStyles();
                        // Setup auto-minimize
                        if (this.styles.autoMinimize && this.styles.autoMinimize > 0) {
                            this.setupAutoMinimize();
                        }
                        // Expose API
                        this.exposeAPI();
                        if (this.onReady)
                            this.onReady();
                        if (this.debug)
                            console.log('[Sandia Widget v3.0] Initialized successfully');
                        return [3 /*break*/, 5];
                    case 4:
                        error_1 = _b.sent();
                        console.error('[Sandia Widget v3.0] Initialization failed:', error_1);
                        if (this.onError)
                            this.onError(error_1);
                        return [3 /*break*/, 5];
                    case 5: return [2 /*return*/];
                }
            });
        });
    };
    SandiaVanillaChatbot.prototype.validateAccess = function () {
        return __awaiter(this, void 0, void 0, function () {
            var headers, response, error, error_2;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        _a.trys.push([0, 4, , 5]);
                        headers = {
                            'Content-Type': 'application/json'
                        };
                        if (this.shareToken) {
                            headers['x-share-token'] = this.shareToken;
                        }
                        if (this.version) {
                            headers['x-widget-version'] = this.version;
                        }
                        return [4 /*yield*/, fetch("".concat(this.apiUrl, "/api/chatbot/public/").concat(this.chatbotId, "/config"), {
                                method: 'GET',
                                headers: headers
                            })];
                    case 1:
                        response = _a.sent();
                        if (!!response.ok) return [3 /*break*/, 3];
                        return [4 /*yield*/, response.json()];
                    case 2:
                        error = _a.sent();
                        if (response.status === 402) {
                            this.handleSubscriptionError(error);
                            return [2 /*return*/, false];
                        }
                        if (response.status === 403 && !this.shareToken) {
                            console.warn('[Sandia Widget v3.0] Chatbot may require authentication or is not public.');
                            return [2 /*return*/, true]; // Still try to render for testing
                        }
                        throw new Error(error.message || 'Access denied');
                    case 3: return [2 /*return*/, true];
                    case 4:
                        error_2 = _a.sent();
                        console.error('[Sandia Widget v3.0] Access validation failed:', error_2);
                        return [2 /*return*/, true]; // Still try to render for development/testing
                    case 5: return [2 /*return*/];
                }
            });
        });
    };
    SandiaVanillaChatbot.prototype.handleSubscriptionError = function (error) {
        console.warn('[Sandia Widget v3.0] Subscription limit reached:', error);
        if (this.onSubscriptionError) {
            this.onSubscriptionError({
                message: error.message || 'Subscription limit reached',
                upgradeRequired: error.upgradeRequired
            });
        }
        this.showSubscriptionNotification(error);
    };
    SandiaVanillaChatbot.prototype.showSubscriptionNotification = function (error) {
        var existing = document.getElementById('sandia-subscription-notification');
        if (existing)
            existing.remove();
        var notification = document.createElement('div');
        notification.id = 'sandia-subscription-notification';
        var position = this.styles.position || 'bottom-right';
        notification.style.cssText = "\n      position: fixed;\n      ".concat(position.includes('bottom') ? 'bottom: 20px' : 'top: 20px', ";\n      ").concat(position.includes('right') ? 'right: 20px' : 'left: 20px', ";\n      background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);\n      color: white;\n      padding: 16px 20px;\n      border-radius: 12px;\n      box-shadow: 0 8px 32px rgba(0,0,0,0.1);\n      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n      font-size: 14px;\n      max-width: 320px;\n      z-index: 10001;\n      cursor: pointer;\n      transition: all 0.3s ease;\n      animation: sandia-notification-in 0.5s ease;\n    ");
        notification.innerHTML = "\n      <div style=\"display: flex; align-items: center; gap: 12px;\">\n        <div style=\"\n          width: 40px;\n          height: 40px;\n          background: rgba(255,255,255,0.2);\n          border-radius: 50%;\n          display: flex;\n          align-items: center;\n          justify-content: center;\n          font-size: 18px;\n        \">\u26A0\uFE0F</div>\n        <div style=\"flex: 1;\">\n          <div style=\"font-weight: 600; margin-bottom: 4px;\">\n            Chatbot Temporarily Unavailable\n          </div>\n          <div style=\"font-size: 12px; opacity: 0.9; line-height: 1.4;\">\n            ".concat(error.message || 'This chatbot has reached its usage limits. Please try again later.', "\n          </div>\n        </div>\n      </div>\n      <div style=\"\n        margin-top: 12px;\n        padding-top: 12px;\n        border-top: 1px solid rgba(255,255,255,0.2);\n        font-size: 11px;\n        opacity: 0.8;\n        text-align: center;\n      \">\n        Powered by Sandia AI\n      </div>\n    ");
        setTimeout(function () {
            if (notification.parentNode) {
                notification.remove();
            }
        }, 10000);
        notification.addEventListener('click', function () {
            notification.remove();
        });
        document.body.appendChild(notification);
    };
    SandiaVanillaChatbot.prototype.createWidget = function () {
        var _this = this;
        this.container = document.createElement('div');
        this.container.id = 'sandia-chatbot-widget-v3';
        this.container.className = 'sandia-widget-container';
        this.container.style.cssText = "\n      position: fixed;\n      z-index: 9999;\n      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n      font-size: 14px;\n      line-height: 1.4;\n      color: ".concat(this.styles.textColor, ";\n      text-rendering: optimizeLegibility;\n      -webkit-font-smoothing: antialiased;\n      -moz-osx-font-smoothing: grayscale;\n    ");
        this.setPosition();
        this.createChatBubble();
        this.createChatWindow();
        document.body.appendChild(this.container);
        // Trigger initial animation
        requestAnimationFrame(function () {
            var _a;
            (_a = _this.container) === null || _a === void 0 ? void 0 : _a.classList.add('sandia-widget-loaded');
        });
    };
    SandiaVanillaChatbot.prototype.createChatBubble = function () {
        var _this = this;
        var _a;
        var bubbleSize = this.getBubbleSize();
        var themeStyles = this.getThemeStyles();
        var bubble = document.createElement('div');
        bubble.id = 'sandia-chat-bubble';
        bubble.className = "sandia-chat-bubble sandia-theme-".concat(this.styles.theme, " sandia-shadow-").concat(this.styles.shadowStyle);
        bubble.style.cssText = "\n      width: ".concat(bubbleSize.width, ";\n      height: ").concat(bubbleSize.height, ";\n      border-radius: ").concat(this.styles.borderRadius, "%;\n      background: ").concat(themeStyles.background, ";\n      color: white;\n      border: ").concat(themeStyles.border, ";\n      cursor: pointer;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      box-shadow: ").concat(this.getShadowStyle(), ";\n      transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);\n      position: relative;\n      overflow: hidden;\n      outline: none;\n      font-size: ").concat(bubbleSize.fontSize, ";\n      will-change: transform;\n    ");
        // Add ARIA attributes
        bubble.setAttribute('role', 'button');
        bubble.setAttribute('tabindex', '0');
        bubble.setAttribute('aria-label', 'Open chat assistant');
        // Create pulse rings for animation
        if (this.styles.showPulse && this.styles.animation !== 'none') {
            this.createPulseRings(bubble);
        }
        // Create bubble icon/avatar
        var icon = document.createElement('div');
        icon.className = 'sandia-bubble-icon';
        icon.style.cssText = "\n      position: relative;\n      z-index: 2;\n      transition: transform 0.3s ease;\n    ";
        if (this.styles.showAvatar && this.styles.customAvatar) {
            var avatar = document.createElement('img');
            avatar.src = this.styles.customAvatar;
            avatar.style.cssText = "\n        width: ".concat(parseInt(bubbleSize.width) * 0.6, "px;\n        height: ").concat(parseInt(bubbleSize.height) * 0.6, "px;\n        border-radius: 50%;\n        object-fit: cover;\n      ");
            icon.appendChild(avatar);
        }
        else {
            icon.textContent = this.styles.customIcon || '💬';
        }
        bubble.appendChild(icon);
        // Create badge for unread count
        if (this.styles.showBadge) {
            var badge = document.createElement('div');
            badge.id = 'sandia-unread-badge';
            badge.className = 'sandia-badge';
            badge.style.cssText = "\n        position: absolute;\n        top: -6px;\n        right: -6px;\n        background: #ef4444;\n        color: white;\n        border-radius: 50%;\n        min-width: 20px;\n        height: 20px;\n        display: none;\n        align-items: center;\n        justify-content: center;\n        font-size: 11px;\n        font-weight: 600;\n        border: 2px solid ".concat(this.styles.backgroundColor, ";\n        animation: sandia-badge-initial 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);\n      ");
            bubble.appendChild(badge);
        }
        // Add event listeners
        bubble.addEventListener('click', function () { return _this.toggleChat(); });
        bubble.addEventListener('keydown', function (e) {
            if (e.key === 'Enter' || e.key === ' ') {
                e.preventDefault();
                _this.toggleChat();
            }
        });
        // Hover effects
        bubble.addEventListener('mouseenter', function () {
            if (_this.styles.animation !== 'none') {
                icon.style.transform = 'scale(1.1) rotate(5deg)';
            }
        });
        bubble.addEventListener('mouseleave', function () {
            icon.style.transform = 'scale(1) rotate(0deg)';
        });
        (_a = this.container) === null || _a === void 0 ? void 0 : _a.appendChild(bubble);
    };
    SandiaVanillaChatbot.prototype.createChatWindow = function () {
        var _a;
        var windowSize = this.getWindowSize();
        this.getThemeStyles();
        var window = document.createElement('div');
        window.id = 'sandia-chat-window';
        window.className = "sandia-chat-window sandia-theme-".concat(this.styles.theme);
        window.style.cssText = "\n      position: absolute;\n      ".concat(this.getChatWindowPosition(), ";\n      width: ").concat(windowSize.width, ";\n      height: ").concat(windowSize.height, ";\n      background: ").concat(this.styles.backgroundColor, ";\n      border-radius: 16px;\n      box-shadow: ").concat(this.getShadowStyle(), ";\n      display: none;\n      flex-direction: column;\n      overflow: hidden;\n      border: ").concat(this.styles.darkMode ? '1px solid #374151' : '1px solid #e5e7eb', ";\n      backdrop-filter: blur(20px);\n      -webkit-backdrop-filter: blur(20px);\n      transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);\n    ");
        // Create header
        this.createChatHeader(window);
        // Create messages container
        this.createMessagesContainer(window);
        // Create input container
        this.createInputContainer(window);
        (_a = this.container) === null || _a === void 0 ? void 0 : _a.appendChild(window);
    };
    SandiaVanillaChatbot.prototype.createChatHeader = function (window) {
        var _this = this;
        var header = document.createElement('div');
        header.className = 'sandia-chat-header';
        header.style.cssText = "\n      padding: 20px;\n      background: linear-gradient(135deg, ".concat(this.styles.primaryColor, " 0%, ").concat(this.adjustColor(this.styles.primaryColor, -20), " 100%);\n      color: white;\n      display: flex;\n      align-items: center;\n      justify-content: space-between;\n      position: relative;\n      overflow: hidden;\n    ");
        // Header content
        var headerContent = document.createElement('div');
        headerContent.style.cssText = "\n      display: flex;\n      align-items: center;\n      gap: 12px;\n      flex: 1;\n    ";
        // Avatar/Icon
        if (this.styles.showAvatar) {
            var avatar = document.createElement('div');
            avatar.style.cssText = "\n        width: 40px;\n        height: 40px;\n        border-radius: 50%;\n        background: rgba(255, 255, 255, 0.2);\n        display: flex;\n        align-items: center;\n        justify-content: center;\n        font-size: 20px;\n      ";
            avatar.textContent = this.styles.customIcon || '💬';
            headerContent.appendChild(avatar);
        }
        // Title and status
        var titleContainer = document.createElement('div');
        titleContainer.innerHTML = "\n      <h3 style=\"margin: 0; font-size: 16px; font-weight: 600;\">Chat Assistant</h3>\n      <div style=\"display: flex; align-items: center; gap: 6px; margin-top: 2px;\">\n        <div style=\"\n          width: 8px;\n          height: 8px;\n          border-radius: 50%;\n          background: #10b981;\n          animation: sandia-online-pulse 2s infinite;\n        \"></div>\n        <span style=\"font-size: 12px; opacity: 0.9;\">Online now</span>\n      </div>\n    ";
        headerContent.appendChild(titleContainer);
        header.appendChild(headerContent);
        // Header buttons
        var headerButtons = document.createElement('div');
        headerButtons.style.cssText = "\n      display: flex;\n      gap: 8px;\n    ";
        // Minimize button
        var minimizeBtn = this.createHeaderButton('−', 'Minimize chat', function () { return _this.minimizeChat(); });
        headerButtons.appendChild(minimizeBtn);
        // Close button
        var closeBtn = this.createHeaderButton('✕', 'Close chat', function () { return _this.closeChat(); });
        headerButtons.appendChild(closeBtn);
        header.appendChild(headerButtons);
        window.appendChild(header);
    };
    SandiaVanillaChatbot.prototype.createHeaderButton = function (icon, label, onClick) {
        var button = document.createElement('button');
        button.style.cssText = "\n      width: 32px;\n      height: 32px;\n      border: none;\n      background: rgba(255, 255, 255, 0.1);\n      color: white;\n      border-radius: 8px;\n      cursor: pointer;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      font-size: 14px;\n      transition: all 0.2s ease;\n      outline: none;\n    ";
        button.textContent = icon;
        button.setAttribute('aria-label', label);
        button.addEventListener('click', onClick);
        button.addEventListener('mouseenter', function () {
            button.style.background = 'rgba(255, 255, 255, 0.2)';
        });
        button.addEventListener('mouseleave', function () {
            button.style.background = 'rgba(255, 255, 255, 0.1)';
        });
        return button;
    };
    SandiaVanillaChatbot.prototype.createMessagesContainer = function (window) {
        var _this = this;
        var container = document.createElement('div');
        container.id = 'sandia-messages-container';
        container.className = 'sandia-scroll-container';
        container.style.cssText = "\n      flex: 1;\n      padding: 20px;\n      overflow-y: auto;\n      display: flex;\n      flex-direction: column;\n      gap: 16px;\n      background: ".concat(this.styles.darkMode ?
            'linear-gradient(to bottom, #1f2937 0%, #111827 100%)' :
            'linear-gradient(to bottom, #f9fafb 0%, #ffffff 100%)', ";\n    ");
        // Add scroll listener for last seen tracking
        container.addEventListener('scroll', function () {
            _this.lastActivity = Date.now();
        });
        // Show welcome message if no messages
        if (this.messages.length === 0) {
            this.showWelcomeMessage(container);
        }
        else {
            this.renderMessages(container);
        }
        window.appendChild(container);
    };
    SandiaVanillaChatbot.prototype.showWelcomeMessage = function (container) {
        var _this = this;
        var welcome = document.createElement('div');
        welcome.style.cssText = "\n      text-align: center;\n      padding: 40px 20px;\n      color: ".concat(this.styles.darkMode ? '#9ca3af' : '#6b7280', ";\n    ");
        welcome.innerHTML = "\n      <div style=\"\n        width: 80px;\n        height: 80px;\n        margin: 0 auto 16px;\n        border-radius: 50%;\n        background: linear-gradient(135deg, ".concat(this.styles.primaryColor, " 0%, ").concat(this.adjustColor(this.styles.primaryColor, -20), " 100%);\n        display: flex;\n        align-items: center;\n        justify-content: center;\n        font-size: 32px;\n        color: white;\n        box-shadow: 0 8px 32px ").concat(this.styles.primaryColor, "40;\n      \">\n        ").concat(this.styles.customIcon, "\n      </div>\n      <h4 style=\"margin: 0 0 8px; font-size: 18px; font-weight: 600; color: ").concat(this.styles.textColor, ";\">\n        Welcome to Chat Assistant\n      </h4>\n      <p style=\"margin: 0 0 20px; font-size: 14px; line-height: 1.5;\">\n        ").concat(this.styles.greeting, "\n      </p>\n    ");
        // Add quick actions
        if (this.chatConfig.quickReplies && this.chatConfig.quickReplies.length > 0) {
            var quickActions_1 = document.createElement('div');
            quickActions_1.style.cssText = "\n        display: flex;\n        flex-wrap: wrap;\n        gap: 8px;\n        justify-content: center;\n      ";
            this.chatConfig.quickReplies.slice(0, 3).forEach(function (reply) {
                var button = document.createElement('button');
                button.style.cssText = "\n          padding: 8px 16px;\n          background: ".concat(_this.styles.primaryColor, ";\n          color: white;\n          border: none;\n          border-radius: 20px;\n          cursor: pointer;\n          font-size: 12px;\n          transition: all 0.2s ease;\n          outline: none;\n        ");
                button.textContent = reply;
                button.addEventListener('click', function () { return _this.sendQuickReply(reply); });
                quickActions_1.appendChild(button);
            });
            welcome.appendChild(quickActions_1);
        }
        container.appendChild(welcome);
    };
    SandiaVanillaChatbot.prototype.createInputContainer = function (window) {
        var _this = this;
        var container = document.createElement('div');
        container.className = 'sandia-input-container';
        container.style.cssText = "\n      padding: 20px;\n      border-top: 1px solid ".concat(this.styles.darkMode ? '#374151' : '#e5e7eb', ";\n      background: ").concat(this.styles.backgroundColor, ";\n    ");
        // Create input wrapper
        var inputWrapper = document.createElement('div');
        inputWrapper.style.cssText = "\n      display: flex;\n      align-items: end;\n      gap: 12px;\n      position: relative;\n    ";
        // Create textarea
        var textarea = document.createElement('textarea');
        textarea.id = 'sandia-message-input';
        textarea.placeholder = 'Type your message...';
        textarea.style.cssText = "\n      flex: 1;\n      min-height: 44px;\n      max-height: 120px;\n      padding: 12px 16px;\n      border: 2px solid ".concat(this.styles.darkMode ? '#374151' : '#e5e7eb', ";\n      border-radius: 24px;\n      resize: none;\n      outline: none;\n      font-family: inherit;\n      font-size: 14px;\n      line-height: 1.4;\n      background: ").concat(this.styles.darkMode ? '#1f2937' : '#ffffff', ";\n      color: ").concat(this.styles.textColor, ";\n      transition: all 0.2s ease;\n    ");
        // Auto-resize functionality
        textarea.addEventListener('input', function () {
            textarea.style.height = 'auto';
            textarea.style.height = Math.min(textarea.scrollHeight, 120) + 'px';
            // Trigger typing indicator
            if (_this.onTyping)
                _this.onTyping(true);
            if (_this.typingTimeout)
                clearTimeout(_this.typingTimeout);
            _this.typingTimeout = setTimeout(function () {
                if (_this.onTyping)
                    _this.onTyping(false);
            }, 1000);
        });
        // Focus styles
        textarea.addEventListener('focus', function () {
            textarea.style.borderColor = _this.styles.primaryColor;
        });
        textarea.addEventListener('blur', function () {
            textarea.style.borderColor = _this.styles.darkMode ? '#374151' : '#e5e7eb';
        });
        // Send on Enter (not Shift+Enter)
        textarea.addEventListener('keydown', function (e) {
            if (e.key === 'Enter' && !e.shiftKey) {
                e.preventDefault();
                _this.sendMessage();
            }
        });
        inputWrapper.appendChild(textarea);
        // Create send button
        var sendButton = document.createElement('button');
        sendButton.id = 'sandia-send-button';
        sendButton.style.cssText = "\n      width: 44px;\n      height: 44px;\n      border: none;\n      border-radius: 50%;\n      background: ".concat(this.styles.primaryColor, ";\n      color: white;\n      cursor: pointer;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      font-size: 16px;\n      transition: all 0.2s ease;\n      outline: none;\n      box-shadow: 0 2px 8px ").concat(this.styles.primaryColor, "40;\n    ");
        sendButton.innerHTML = '➤';
        sendButton.setAttribute('aria-label', 'Send message');
        sendButton.addEventListener('click', function () { return _this.sendMessage(); });
        // Send button hover effects
        sendButton.addEventListener('mouseenter', function () {
            sendButton.style.transform = 'scale(1.05)';
            sendButton.style.boxShadow = "0 4px 16px ".concat(_this.styles.primaryColor, "60");
        });
        sendButton.addEventListener('mouseleave', function () {
            sendButton.style.transform = 'scale(1)';
            sendButton.style.boxShadow = "0 2px 8px ".concat(_this.styles.primaryColor, "40");
        });
        inputWrapper.appendChild(sendButton);
        container.appendChild(inputWrapper);
        // Add "Powered by Sandia" footer if branding enabled
        if (this.styles.brandingEnabled) {
            var footer = document.createElement('div');
            footer.style.cssText = "\n        margin-top: 12px;\n        text-align: center;\n        font-size: 11px;\n        color: ".concat(this.styles.darkMode ? '#6b7280' : '#9ca3af', ";\n        opacity: 0.8;\n      ");
            footer.innerHTML = "\n        <a href=\"https://sandia.chat\" target=\"_blank\" style=\"\n          color: inherit;\n          text-decoration: none;\n          display: inline-flex;\n          align-items: center;\n          gap: 4px;\n        \">\n          <span>\u2728</span>\n          Powered by Sandia AI\n        </a>\n      ";
            container.appendChild(footer);
        }
        window.appendChild(container);
    };
    // Continue with remaining methods...
    SandiaVanillaChatbot.prototype.sendMessage = function () {
        return __awaiter(this, void 0, void 0, function () {
            var input, content, headers, requestBody, response, errorData, data, error_3;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        input = document.getElementById('sandia-message-input');
                        if (!input || this.isLoading)
                            return [2 /*return*/];
                        content = input.value.trim();
                        if (!content)
                            return [2 /*return*/];
                        this.isLoading = true;
                        this.lastActivity = Date.now();
                        // Clear typing timeout
                        if (this.typingTimeout) {
                            clearTimeout(this.typingTimeout);
                            if (this.onTyping)
                                this.onTyping(false);
                        }
                        // Add user message
                        this.addMessage(content, 'user');
                        input.value = '';
                        input.style.height = 'auto';
                        // Show typing indicator
                        if (this.styles.showTypingIndicator) {
                            this.showTypingIndicator();
                        }
                        _a.label = 1;
                    case 1:
                        _a.trys.push([1, 6, 7, 8]);
                        headers = {
                            'Content-Type': 'application/json',
                        };
                        if (this.shareToken) {
                            headers['x-share-token'] = this.shareToken;
                        }
                        if (this.version) {
                            headers['x-widget-version'] = this.version;
                        }
                        requestBody = {
                            message: content,
                            timestamp: new Date().toISOString(),
                            metadata: __assign({ conversationId: this.conversationId, userAgent: navigator.userAgent }, this.metadata)
                        };
                        return [4 /*yield*/, fetch("".concat(this.apiUrl, "/api/chatbot/public/").concat(this.chatbotId), {
                                method: 'POST',
                                headers: headers,
                                body: JSON.stringify(requestBody)
                            })];
                    case 2:
                        response = _a.sent();
                        this.hideTypingIndicator();
                        if (!!response.ok) return [3 /*break*/, 4];
                        return [4 /*yield*/, response.json()];
                    case 3:
                        errorData = _a.sent();
                        if (response.status === 402) {
                            this.handleSubscriptionError(errorData);
                            return [2 /*return*/];
                        }
                        else if (response.status === 429) {
                            this.addMessage(errorData.message || 'Rate limit exceeded. Please wait before sending another message.', 'assistant', true);
                            return [2 /*return*/];
                        }
                        else if (response.status === 403) {
                            this.addMessage(errorData.message || 'Access denied. This chatbot may be restricted.', 'assistant', true);
                            return [2 /*return*/];
                        }
                        throw new Error(errorData.message || "HTTP error! status: ".concat(response.status));
                    case 4: return [4 /*yield*/, response.json()];
                    case 5:
                        data = _a.sent();
                        // Update conversation ID if provided
                        if (data.conversationId) {
                            this.conversationId = data.conversationId;
                        }
                        // Add bot response
                        this.addMessage(data.response || data.message || 'Sorry, I could not process your request.', 'assistant');
                        // Play notification sound
                        if (this.styles.soundEnabled) {
                            this.playSound('messageReceived');
                        }
                        // Show notification if chat is closed
                        if (!this.isOpen && this.styles.notificationsEnabled) {
                            this.showNotification('New message', data.response || data.message);
                            this.updateBadge(this.unreadCount + 1);
                        }
                        return [3 /*break*/, 8];
                    case 6:
                        error_3 = _a.sent();
                        this.hideTypingIndicator();
                        console.error('[Sandia Widget v3.0] Message sending failed:', error_3);
                        this.addMessage('Sorry, I encountered an error. Please try again.', 'assistant', true);
                        if (this.onError) {
                            this.onError(error_3);
                        }
                        return [3 /*break*/, 8];
                    case 7:
                        this.isLoading = false;
                        return [7 /*endfinally*/];
                    case 8: return [2 /*return*/];
                }
            });
        });
    };
    SandiaVanillaChatbot.prototype.addMessage = function (content, role, isError) {
        var message = {
            id: Date.now().toString(),
            content: content,
            role: role,
            timestamp: new Date()
        };
        this.messages.push(message);
        // Limit message history
        if (this.styles.maxMessages && this.messages.length > this.styles.maxMessages) {
            this.messages = this.messages.slice(-this.styles.maxMessages);
        }
        // Save to localStorage if persistence enabled
        if (this.styles.messagePersistence) {
            this.saveMessageHistory();
        }
        // Render message
        var container = document.getElementById('sandia-messages-container');
        if (container) {
            // Remove welcome message if exists
            var welcome = container.querySelector('[style*="text-align: center"]');
            if (welcome)
                welcome.remove();
            var messageElement = this.createMessage(message, isError);
            container.appendChild(messageElement);
            this.scrollToBottom();
        }
        // Trigger callback
        if (this.onMessage) {
            this.onMessage({
                content: message.content,
                role: message.role,
                timestamp: message.timestamp
            });
        }
    };
    SandiaVanillaChatbot.prototype.createMessage = function (message, isError) {
        var _this = this;
        var isUser = message.role === 'user';
        var messageDiv = document.createElement('div');
        messageDiv.className = "sandia-message sandia-message-".concat(isUser ? 'user' : 'assistant');
        messageDiv.style.cssText = "\n      display: flex;\n      ".concat(isUser ? 'justify-content: flex-end' : 'justify-content: flex-start', ";\n      margin-bottom: ").concat(this.styles.showTimestamps ? '8px' : '4px', ";\n      animation: sandia-message-in 0.3s ease;\n    ");
        var bubble = document.createElement('div');
        bubble.className = 'sandia-message-bubble';
        bubble.style.cssText = "\n      max-width: 80%;\n      padding: 12px 16px;\n      border-radius: 18px;\n      ".concat(isUser ?
            "background: ".concat(this.styles.primaryColor, "; color: white; border-bottom-right-radius: 4px;") :
            "background: ".concat(this.styles.darkMode ? '#374151' : '#f1f3f4', "; color: ").concat(this.styles.textColor, "; border-bottom-left-radius: 4px;"), "\n      ").concat(isError ? 'border: 1px solid #ef4444;' : '', "\n      word-wrap: break-word;\n      line-height: 1.4;\n      position: relative;\n      box-shadow: 0 1px 2px rgba(0,0,0,0.1);\n    ");
        // Add message content with basic markdown parsing
        bubble.innerHTML = this.parseMessageContent(message.content);
        // Add copy button for assistant messages
        if (!isUser && !isError) {
            var copyBtn_1 = document.createElement('button');
            copyBtn_1.style.cssText = "\n        position: absolute;\n        top: -8px;\n        right: -8px;\n        width: 24px;\n        height: 24px;\n        border: none;\n        border-radius: 50%;\n        background: ".concat(this.styles.primaryColor, ";\n        color: white;\n        cursor: pointer;\n        font-size: 12px;\n        display: none;\n        align-items: center;\n        justify-content: center;\n        opacity: 0.8;\n        transition: all 0.2s ease;\n      ");
            copyBtn_1.innerHTML = '📋';
            copyBtn_1.addEventListener('click', function () { return _this.copyToClipboard(message.content); });
            bubble.addEventListener('mouseenter', function () {
                copyBtn_1.style.display = 'flex';
            });
            bubble.addEventListener('mouseleave', function () {
                copyBtn_1.style.display = 'none';
            });
            bubble.appendChild(copyBtn_1);
        }
        messageDiv.appendChild(bubble);
        // Add timestamp if enabled
        if (this.styles.showTimestamps) {
            var timestamp = document.createElement('div');
            timestamp.style.cssText = "\n        font-size: 11px;\n        color: ".concat(this.styles.darkMode ? '#6b7280' : '#9ca3af', ";\n        margin-top: 4px;\n        ").concat(isUser ? 'text-align: right' : 'text-align: left', ";\n      ");
            timestamp.textContent = this.formatTime(message.timestamp);
            messageDiv.appendChild(timestamp);
        }
        return messageDiv;
    };
    // Helper methods
    SandiaVanillaChatbot.prototype.getBubbleSize = function () {
        switch (this.styles.size) {
            case 'sm': return { width: '48px', height: '48px', fontSize: '20px' };
            case 'lg': return { width: '64px', height: '64px', fontSize: '28px' };
            default: return { width: '56px', height: '56px', fontSize: '24px' };
        }
    };
    SandiaVanillaChatbot.prototype.getWindowSize = function () {
        var isMobile = window.innerWidth <= 768;
        if (isMobile && this.styles.mobileFullScreen) {
            return { width: '100vw', height: '100vh' };
        }
        return { width: '380px', height: '600px' };
    };
    SandiaVanillaChatbot.prototype.setPosition = function () {
        if (!this.container)
            return;
        var position = this.styles.position || 'bottom-right';
        var offset = '24px';
        this.container.style.top = 'auto';
        this.container.style.bottom = 'auto';
        this.container.style.left = 'auto';
        this.container.style.right = 'auto';
        switch (position) {
            case 'bottom-left':
                this.container.style.bottom = offset;
                this.container.style.left = offset;
                break;
            case 'top-right':
                this.container.style.top = offset;
                this.container.style.right = offset;
                break;
            case 'top-left':
                this.container.style.top = offset;
                this.container.style.left = offset;
                break;
            default:
                this.container.style.bottom = offset;
                this.container.style.right = offset;
                break;
        }
    };
    SandiaVanillaChatbot.prototype.getChatWindowPosition = function () {
        var position = this.styles.position || 'bottom-right';
        var isMobile = window.innerWidth <= 768;
        if (isMobile && this.styles.mobileFullScreen) {
            return 'top: 0; left: 0;';
        }
        switch (position) {
            case 'bottom-left':
                return 'bottom: 70px; left: 0;';
            case 'top-right':
                return 'top: 70px; right: 0;';
            case 'top-left':
                return 'top: 70px; left: 0;';
            default:
                return 'bottom: 70px; right: 0;';
        }
    };
    SandiaVanillaChatbot.prototype.getThemeStyles = function () {
        var primary = this.styles.primaryColor;
        switch (this.styles.theme) {
            case 'gradient':
                return {
                    background: "linear-gradient(135deg, ".concat(primary, " 0%, ").concat(this.adjustColor(primary, 30), " 100%)"),
                    border: 'none'
                };
            case 'classic':
                return {
                    background: primary,
                    border: "2px solid ".concat(this.adjustColor(primary, -20))
                };
            case 'minimal':
                return {
                    background: this.styles.darkMode ? '#374151' : '#f3f4f6',
                    border: "1px solid ".concat(primary)
                };
            default: // modern
                return {
                    background: primary,
                    border: 'none'
                };
        }
    };
    SandiaVanillaChatbot.prototype.getShadowStyle = function () {
        var primary = this.styles.primaryColor;
        switch (this.styles.shadowStyle) {
            case 'hard':
                return '0 4px 12px rgba(0,0,0,0.3)';
            case 'glow':
                return "0 0 20px ".concat(primary, "40, 0 0 40px ").concat(primary, "20");
            case 'none':
                return 'none';
            default: // soft
                return '0 4px 20px rgba(0,0,0,0.15)';
        }
    };
    SandiaVanillaChatbot.prototype.adjustColor = function (color, percent) {
        var num = parseInt(color.replace("#", ""), 16);
        var amt = Math.round(2.55 * percent);
        var R = (num >> 16) + amt;
        var G = (num >> 8 & 0x00FF) + amt;
        var B = (num & 0x0000FF) + amt;
        return "#" + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 +
            (G < 255 ? G < 1 ? 0 : G : 255) * 0x100 +
            (B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1);
    };
    SandiaVanillaChatbot.prototype.formatTime = function (date) {
        var now = new Date();
        var diff = now.getTime() - date.getTime();
        var minutes = Math.floor(diff / 60000);
        if (minutes < 1)
            return 'Just now';
        if (minutes < 60)
            return "".concat(minutes, "m ago");
        if (minutes < 1440)
            return "".concat(Math.floor(minutes / 60), "h ago");
        return date.toLocaleDateString();
    };
    SandiaVanillaChatbot.prototype.parseMessageContent = function (content) {
        return content
            .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
            .replace(/\*(.*?)\*/g, '<em>$1</em>')
            .replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" target="_blank" rel="noopener">$1</a>');
    };
    SandiaVanillaChatbot.prototype.scrollToBottom = function () {
        var container = document.getElementById('sandia-messages-container');
        if (container) {
            container.scrollTop = container.scrollHeight;
        }
    };
    SandiaVanillaChatbot.prototype.copyToClipboard = function (text) {
        var _this = this;
        navigator.clipboard.writeText(text).then(function () {
            _this.showToast('Message copied to clipboard');
        });
    };
    SandiaVanillaChatbot.prototype.showToast = function (message) {
        var toast = document.createElement('div');
        toast.style.cssText = "\n      position: fixed;\n      top: 20px;\n      left: 50%;\n      transform: translateX(-50%);\n      background: rgba(0, 0, 0, 0.8);\n      color: white;\n      padding: 8px 16px;\n      border-radius: 20px;\n      font-size: 12px;\n      z-index: 10002;\n      animation: sandia-toast-in 0.3s ease;\n    ";
        toast.textContent = message;
        document.body.appendChild(toast);
        setTimeout(function () {
            toast.remove();
        }, 2000);
    };
    SandiaVanillaChatbot.prototype.playSound = function (type) {
        if (!this.styles.soundEnabled)
            return;
        try {
            var audio = new Audio(this.sounds[type]);
            audio.volume = 0.3;
            audio.play().catch(function () { }); // Ignore audio play errors
        }
        catch (error) {
            // Ignore audio errors
        }
    };
    SandiaVanillaChatbot.prototype.showNotification = function (title, body) {
        if (!this.styles.notificationsEnabled || this.notificationPermission !== 'granted')
            return;
        try {
            new Notification(title, {
                body: body.substring(0, 100) + (body.length > 100 ? '...' : ''),
                icon: '/favicon.ico',
                tag: 'sandia-chatbot'
            });
        }
        catch (error) {
            // Ignore notification errors
        }
    };
    SandiaVanillaChatbot.prototype.updateBadge = function (count) {
        this.unreadCount = count;
        var badge = document.getElementById('sandia-unread-badge');
        if (badge) {
            if (count > 0) {
                badge.style.display = 'flex';
                badge.textContent = count > 99 ? '99+' : count.toString();
            }
            else {
                badge.style.display = 'none';
            }
        }
    };
    SandiaVanillaChatbot.prototype.loadMessageHistory = function () {
        try {
            var stored = localStorage.getItem("sandia-chatbot-".concat(this.chatbotId));
            if (stored) {
                var data = JSON.parse(stored);
                this.messages = data.messages || [];
                this.conversationId = data.conversationId || null;
            }
        }
        catch (error) {
            // Ignore localStorage errors
        }
    };
    SandiaVanillaChatbot.prototype.saveMessageHistory = function () {
        try {
            localStorage.setItem("sandia-chatbot-".concat(this.chatbotId), JSON.stringify({
                messages: this.messages.slice(-50), // Keep last 50 messages
                conversationId: this.conversationId,
                timestamp: Date.now()
            }));
        }
        catch (error) {
            // Ignore localStorage errors
        }
    };
    SandiaVanillaChatbot.prototype.createPulseRings = function (bubble) {
        for (var i = 0; i < 3; i++) {
            var ring = document.createElement('div');
            ring.className = "sandia-pulse-ring-".concat(i);
            ring.style.cssText = "\n        position: absolute;\n        top: 50%;\n        left: 50%;\n        transform: translate(-50%, -50%);\n        border: 2px solid ".concat(this.styles.primaryColor, ";\n        border-radius: 50%;\n        animation: sandia-pulse 2s infinite ").concat(i * 0.5, "s;\n        pointer-events: none;\n      ");
            bubble.appendChild(ring);
        }
    };
    SandiaVanillaChatbot.prototype.showTypingIndicator = function () {
        var container = document.getElementById('sandia-messages-container');
        if (!container)
            return;
        var indicator = document.createElement('div');
        indicator.id = 'sandia-typing-indicator';
        indicator.className = 'sandia-message sandia-message-assistant';
        indicator.style.cssText = "\n      display: flex;\n      justify-content: flex-start;\n      margin-bottom: 8px;\n      animation: sandia-message-in 0.3s ease;\n    ";
        var bubble = document.createElement('div');
        bubble.style.cssText = "\n      background: ".concat(this.styles.darkMode ? '#374151' : '#f1f3f4', ";\n      color: ").concat(this.styles.textColor, ";\n      padding: 12px 16px;\n      border-radius: 18px 18px 18px 4px;\n      display: flex;\n      align-items: center;\n      gap: 4px;\n    ");
        for (var i = 0; i < 3; i++) {
            var dot = document.createElement('div');
            dot.style.cssText = "\n        width: 8px;\n        height: 8px;\n        border-radius: 50%;\n        background: ".concat(this.styles.darkMode ? '#9ca3af' : '#6b7280', ";\n        animation: sandia-dot-pulse 1.4s infinite ").concat(i * 0.2, "s;\n      ");
            bubble.appendChild(dot);
        }
        indicator.appendChild(bubble);
        container.appendChild(indicator);
        this.scrollToBottom();
    };
    SandiaVanillaChatbot.prototype.hideTypingIndicator = function () {
        var indicator = document.getElementById('sandia-typing-indicator');
        if (indicator) {
            indicator.remove();
        }
    };
    SandiaVanillaChatbot.prototype.sendQuickReply = function (reply) {
        var input = document.getElementById('sandia-message-input');
        if (input) {
            input.value = reply;
            this.sendMessage();
        }
    };
    SandiaVanillaChatbot.prototype.renderMessages = function (container) {
        var _this = this;
        this.messages.forEach(function (message) {
            var messageElement = _this.createMessage(message);
            container.appendChild(messageElement);
        });
        this.scrollToBottom();
    };
    SandiaVanillaChatbot.prototype.renderBlockedState = function () {
        this.container = document.createElement('div');
        this.container.id = 'sandia-chatbot-blocked';
        this.container.style.cssText = "\n      position: fixed;\n      z-index: 9999;\n      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n    ";
        this.setPosition();
        var buttonSize = this.getBubbleSize();
        this.container.innerHTML = "\n      <div style=\"\n        width: ".concat(buttonSize.width, ";\n        height: ").concat(buttonSize.height, ";\n        background: #6b7280;\n        border: none;\n        border-radius: ").concat(this.styles.borderRadius, "%;\n        color: white;\n        display: flex;\n        align-items: center;\n        justify-content: center;\n        box-shadow: 0 4px 20px rgba(0,0,0,0.15);\n        font-size: ").concat(buttonSize.fontSize, ";\n        opacity: 0.6;\n        cursor: not-allowed;\n        position: relative;\n      \">\n        \u26A0\uFE0F\n      </div>\n    ");
        document.body.appendChild(this.container);
    };
    SandiaVanillaChatbot.prototype.setupAutoMinimize = function () {
        var _this = this;
        var checkInactivity = function () {
            if (_this.isOpen && !_this.isMinimized) {
                var inactiveTime = Date.now() - _this.lastActivity;
                var autoMinimizeMs = (_this.styles.autoMinimize || 5) * 60 * 1000;
                if (inactiveTime > autoMinimizeMs) {
                    _this.minimizeChat();
                }
            }
        };
        setInterval(checkInactivity, 30000); // Check every 30 seconds
    };
    SandiaVanillaChatbot.prototype.exposeAPI = function () {
        var _this = this;
        window.SandiaChatbotAPI = {
            open: function () { return _this.openChat(); },
            close: function () { return _this.closeChat(); },
            minimize: function () { return _this.minimizeChat(); },
            restore: function () { return _this.restoreChat(); },
            sendMessage: function (message) {
                var input = document.getElementById('sandia-message-input');
                if (input) {
                    input.value = message;
                    _this.sendMessage();
                }
            },
            updateConfig: function (config) {
                _this.styles = __assign(__assign({}, _this.styles), config);
            },
            updateBadge: function (count) { return _this.updateBadge(count); },
            resetUnreadCount: function () { return _this.updateBadge(0); },
            getUnreadCount: function () { return _this.unreadCount; },
            destroy: function () { return _this.destroy(); },
            getConfig: function () { return (__assign({}, _this.styles)); },
            getMessages: function () { return __spreadArray([], _this.messages, true); },
            isOpen: function () { return _this.isOpen; },
            isMinimized: function () { return _this.isMinimized; }
        };
    };
    SandiaVanillaChatbot.prototype.addEnhancedStyles = function () {
        if (document.getElementById('sandia-widget-styles-v3'))
            return;
        var style = document.createElement('style');
        style.id = 'sandia-widget-styles-v3';
        style.textContent = "\n      @keyframes sandia-pulse {\n        0%, 80%, 100% { opacity: 0; transform: translate(-50%, -50%) scale(1); }\n        40% { opacity: 0.3; transform: translate(-50%, -50%) scale(1.3); }\n      }\n      \n      @keyframes sandia-dot-pulse {\n        0%, 80%, 100% { opacity: 0.3; transform: scale(0.8); }\n        40% { opacity: 1; transform: scale(1); }\n      }\n      \n      @keyframes sandia-message-in {\n        from { opacity: 0; transform: translateY(10px); }\n        to { opacity: 1; transform: translateY(0); }\n      }\n      \n      @keyframes sandia-badge-initial {\n        0% { transform: scale(0); }\n        50% { transform: scale(1.2); }\n        100% { transform: scale(1); }\n      }\n      \n      @keyframes sandia-online-pulse {\n        0%, 100% { opacity: 1; }\n        50% { opacity: 0.5; }\n      }\n      \n      @keyframes sandia-notification-in {\n        from { opacity: 0; transform: translateY(-20px); }\n        to { opacity: 1; transform: translateY(0); }\n      }\n      \n      @keyframes sandia-toast-in {\n        from { opacity: 0; transform: translate(-50%, -10px); }\n        to { opacity: 1; transform: translate(-50%, 0); }\n      }\n      \n      .sandia-widget-container {\n        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n        text-rendering: optimizeLegibility;\n        -webkit-font-smoothing: antialiased;\n        -moz-osx-font-smoothing: grayscale;\n      }\n      \n      .sandia-scroll-container {\n        scrollbar-width: thin;\n        scrollbar-color: ".concat(this.styles.darkMode ? '#4b5563 #1f2937' : '#cbd5e1 #f1f5f9', ";\n      }\n      \n      .sandia-scroll-container::-webkit-scrollbar {\n        width: 6px;\n      }\n      \n      .sandia-scroll-container::-webkit-scrollbar-track {\n        background: ").concat(this.styles.darkMode ? '#1f2937' : '#f1f5f9', ";\n        border-radius: 3px;\n      }\n      \n      .sandia-scroll-container::-webkit-scrollbar-thumb {\n        background: ").concat(this.styles.darkMode ? '#4b5563' : '#cbd5e1', ";\n        border-radius: 3px;\n      }\n      \n      .sandia-scroll-container::-webkit-scrollbar-thumb:hover {\n        background: ").concat(this.styles.darkMode ? '#6b7280' : '#94a3b8', ";\n      }\n      \n      @media (max-width: 768px) {\n        .sandia-chat-window {\n          border-radius: ").concat(this.styles.mobileFullScreen ? '0 !important' : '16px', ";\n          ").concat(this.styles.mobileFullScreen ? 'position: fixed !important; top: 0 !important; left: 0 !important; width: 100vw !important; height: 100vh !important;' : '', "\n        }\n        \n        .sandia-message-bubble {\n          max-width: 85% !important;\n        }\n        \n        .sandia-input-container {\n          padding: 16px !important;\n        }\n        \n        #sandia-message-input {\n          font-size: 16px !important; /* Prevent zoom on iOS */\n        }\n      }\n      \n      @media (prefers-reduced-motion: reduce) {\n        *, *::before, *::after {\n          animation-duration: 0.01ms !important;\n          animation-iteration-count: 1 !important;\n          transition-duration: 0.01ms !important;\n        }\n      }\n      \n      @media (prefers-color-scheme: dark) {\n        .sandia-chat-window {\n          border-color: #374151;\n        }\n      }\n      \n      @media print {\n        .sandia-widget-container {\n          display: none !important;\n        }\n      }\n    ");
        document.head.appendChild(style);
    };
    // Public methods
    SandiaVanillaChatbot.prototype.toggleChat = function () {
        if (this.isOpen) {
            this.closeChat();
        }
        else {
            this.openChat();
        }
    };
    SandiaVanillaChatbot.prototype.openChat = function () {
        var window = document.getElementById('sandia-chat-window');
        var bubble = document.getElementById('sandia-chat-bubble');
        var input = document.getElementById('sandia-message-input');
        if (window && bubble) {
            this.isOpen = true;
            this.isMinimized = false;
            this.lastActivity = Date.now();
            window.style.display = 'flex';
            bubble.innerHTML = bubble.innerHTML.replace(this.styles.customIcon || '💬', '✕');
            // Focus input
            setTimeout(function () {
                if (input)
                    input.focus();
            }, 100);
            // Reset unread count
            this.updateBadge(0);
            // Play sound
            if (this.styles.soundEnabled) {
                this.playSound('messageClick');
            }
            if (this.onOpen)
                this.onOpen();
        }
    };
    SandiaVanillaChatbot.prototype.closeChat = function () {
        var window = document.getElementById('sandia-chat-window');
        var bubble = document.getElementById('sandia-chat-bubble');
        if (window && bubble) {
            this.isOpen = false;
            this.isMinimized = false;
            window.style.display = 'none';
            bubble.innerHTML = bubble.innerHTML.replace('✕', this.styles.customIcon || '💬');
            if (this.onClose)
                this.onClose();
        }
    };
    SandiaVanillaChatbot.prototype.minimizeChat = function () {
        var window = document.getElementById('sandia-chat-window');
        if (window && this.isOpen) {
            this.isMinimized = true;
            window.style.display = 'none';
            if (this.onMinimize)
                this.onMinimize();
        }
    };
    SandiaVanillaChatbot.prototype.restoreChat = function () {
        if (this.isMinimized) {
            this.isMinimized = false;
            this.openChat();
            if (this.onRestore)
                this.onRestore();
        }
    };
    SandiaVanillaChatbot.prototype.destroy = function () {
        if (this.container) {
            this.container.remove();
        }
        var styles = document.getElementById('sandia-widget-styles-v3');
        if (styles) {
            styles.remove();
        }
        delete window.SandiaChatbotAPI;
    };
    return SandiaVanillaChatbot;
}());
function initSandiaChatbot(config) {
    var finalConfig = config || window.SandiaChatbot;
    if (!finalConfig || !finalConfig.chatbotId) {
        console.error('Sandia Chatbot v3.0: Missing chatbotId in configuration');
        return;
    }
    new SandiaVanillaChatbot(finalConfig);
}
// Auto-initialize if window.SandiaChatbot is available
if (typeof window !== 'undefined' && window.SandiaChatbot) {
    document.addEventListener('DOMContentLoaded', function () {
        initSandiaChatbot();
    });
}

export { SandiaWidget, initSandiaChatbot };
//# sourceMappingURL=index.esm.js.map