rowsky-chatbot-widget 1.0.5 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/chatbot.mjs CHANGED
@@ -37,69 +37,190 @@ const createWidgetAPI = (baseUrl) => {
37
37
  captureLead: (token, leadData) => request("POST", "/widget/lead", leadData, token)
38
38
  };
39
39
  };
40
- const renderWidget = ({ config, token, api, visitorId, botId }) => {
40
+ const STYLE_ID = "fluxia-widget-styles";
41
+ const CRITICAL_CSS = `
42
+ #fluxia-widget-root{all:initial;font-family:"Inter",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;font-size:14px;line-height:1.5;color:#1f2937;--fw-header:#0f172a;--fw-white:#fff;--fw-green:#22c55e;--fw-red:#ef4444;--fw-red-dark:#dc2626;--fw-text:#1f2937;--fw-gray-100:#f3f4f6;--fw-gray-200:#e5e7eb;--fw-gray-300:#d1d5db;--fw-gray-bg:#fafbfc;--fw-radius:20px;--fw-shadow:0 20px 60px rgba(0,0,0,.25)}
43
+ #fluxia-widget-root *,#fluxia-widget-root *::before,#fluxia-widget-root *::after{box-sizing:border-box;margin:0;padding:0}
44
+ #fluxia-widget-root .fluxia-bubble{position:fixed;bottom:24px;right:24px;z-index:2147483646;width:60px;height:60px;border-radius:50%;border:none;background:linear-gradient(135deg,#ef4444,#dc2626);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:0 8px 24px rgba(239,68,68,.5),0 0 0 4px rgba(255,255,255,.25);transition:transform .3s cubic-bezier(.34,1.56,.64,1),box-shadow .3s,opacity .25s;opacity:1}
45
+ #fluxia-widget-root .fluxia-bubble.fw-hidden{transform:scale(0);opacity:0;pointer-events:none}
46
+ #fluxia-widget-root .fluxia-bubble svg{width:28px;height:28px;fill:#fff;stroke:none}
47
+ #fluxia-widget-root .fluxia-chatbox{position:fixed;bottom:10px;right:10px;z-index:2147483647;width:400px;height:600px;max-height:calc(100vh - 120px);border-radius:var(--fw-radius);background:var(--fw-white);box-shadow:var(--fw-shadow);display:flex;flex-direction:column;overflow:hidden;transform-origin:bottom right;transform:scale(0) translateY(20px);opacity:0;pointer-events:none;transition:transform .35s cubic-bezier(.34,1.56,.64,1),opacity .25s}
48
+ #fluxia-widget-root .fluxia-chatbox.fw-open{transform:scale(1) translateY(0);opacity:1;pointer-events:auto}
49
+ #fluxia-widget-root .fluxia-header{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px 16px;background:var(--fw-header);color:var(--fw-white);flex-shrink:0;border-radius:var(--fw-radius) var(--fw-radius) 0 0}
50
+ #fluxia-widget-root .fluxia-header-info{display:flex;align-items:center;gap:12px;flex:1;min-width:0}
51
+ #fluxia-widget-root .fluxia-avatar{width:42px;height:42px;min-width:42px;border-radius:50%;background:rgba(255,255,255,.12);border:2px solid rgba(34,197,94,.5);display:flex;align-items:center;justify-content:center;font-size:20px;overflow:hidden;color:#fff}
52
+ #fluxia-widget-root .fluxia-avatar img{width:100%;height:100%;object-fit:cover;border-radius:50%}
53
+ #fluxia-widget-root .fluxia-header-text{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}
54
+ #fluxia-widget-root .fluxia-title{font-weight:700;font-size:15px;color:var(--fw-white);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
55
+ #fluxia-widget-root .fluxia-status{font-size:12px;color:var(--fw-green);display:flex;align-items:center;gap:6px;font-weight:600}
56
+ #fluxia-widget-root .fluxia-status-dot{width:7px;height:7px;border-radius:50%;background:var(--fw-green);display:inline-block;animation:fw-pulse 2s ease-in-out infinite}
57
+ @keyframes fw-pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.4;transform:scale(1.3)}}
58
+ #fluxia-widget-root .fluxia-close{width:34px;height:34px;display:flex;align-items:center;justify-content:center;background:rgba(255,255,255,.08);border:none;color:var(--fw-white);cursor:pointer;border-radius:8px;transition:background .2s}
59
+ #fluxia-widget-root .fluxia-close:hover{background:rgba(255,255,255,.18)}
60
+ #fluxia-widget-root .fluxia-close svg{width:16px;height:16px}
61
+ #fluxia-widget-root .fluxia-messages{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:10px;background:var(--fw-white)}
62
+ #fluxia-widget-root .fluxia-msg{max-width:82%;padding:10px 14px;font-size:13.5px;line-height:1.55;word-wrap:break-word;overflow-wrap:break-word;animation:fw-msgIn .3s ease-out}
63
+ @keyframes fw-msgIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
64
+ #fluxia-widget-root .fluxia-msg-assistant{align-self:flex-start;background:var(--fw-gray-100);color:var(--fw-text);border-radius:16px 16px 16px 4px}
65
+ #fluxia-widget-root .fluxia-msg-user{align-self:flex-end;background:var(--fw-header);color:var(--fw-white);border-radius:16px 16px 4px 16px}
66
+ #fluxia-widget-root .fluxia-msg-system{align-self:center;background:#fef3c7;color:#92400e;font-size:12px;padding:8px 14px;border-radius:8px;text-align:center;max-width:90%;border:1px solid #fde68a}
67
+ #fluxia-widget-root .fluxia-typing{display:flex;gap:5px;align-items:center;padding:4px 0}
68
+ #fluxia-widget-root .fluxia-typing-dot{width:7px;height:7px;border-radius:50%;background:#94a3b8;animation:fw-bounce 1.4s infinite ease-in-out}
69
+ #fluxia-widget-root .fluxia-typing-dot:nth-child(2){animation-delay:.16s}
70
+ #fluxia-widget-root .fluxia-typing-dot:nth-child(3){animation-delay:.32s}
71
+ @keyframes fw-bounce{0%,80%,100%{transform:scale(.7);opacity:.4}40%{transform:scale(1.1);opacity:1}}
72
+ #fluxia-widget-root .fluxia-input-area{padding:12px 14px;background:var(--fw-white);border-top:1px solid var(--fw-gray-200);display:flex;align-items:center;gap:10px;flex-shrink:0}
73
+ #fluxia-widget-root .fluxia-input{flex:1;border:1.5px solid var(--fw-gray-300);border-radius:24px;padding:10px 16px;font-size:13px;font-family:inherit;outline:none;color:var(--fw-text);background:var(--fw-gray-bg);transition:border-color .2s,box-shadow .2s}
74
+ #fluxia-widget-root .fluxia-input::placeholder{color:#9ca3af}
75
+ #fluxia-widget-root .fluxia-input:focus{border-color:var(--fw-header);background:var(--fw-white);box-shadow:0 0 0 3px rgba(15,23,42,.06)}
76
+ #fluxia-widget-root .fluxia-input:disabled{opacity:.5;cursor:not-allowed}
77
+ #fluxia-widget-root .fluxia-send{width:40px;height:40px;min-width:40px;border-radius:50%;background:var(--fw-red);color:var(--fw-white);border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background .2s,transform .2s;flex-shrink:0}
78
+ #fluxia-widget-root .fluxia-send:hover{background:var(--fw-red-dark);transform:scale(1.08)}
79
+ #fluxia-widget-root .fluxia-send:active{transform:scale(.92)}
80
+ #fluxia-widget-root .fluxia-send:disabled{opacity:.4;cursor:not-allowed;transform:none}
81
+ #fluxia-widget-root .fluxia-send svg{width:18px;height:18px}
82
+ #fluxia-widget-root .fluxia-powered{text-align:center;padding:8px 0;font-size:11px;color:#9ca3af;background:var(--fw-white);border-top:1px solid var(--fw-gray-200);flex-shrink:0}
83
+ #fluxia-widget-root .fluxia-powered a{color:#6b7280;text-decoration:none;font-weight:600}
84
+ #fluxia-widget-root[data-position="left"] .fluxia-bubble{left:24px;right:auto}
85
+ #fluxia-widget-root[data-position="left"] .fluxia-chatbox{left:24px;right:auto;transform-origin:bottom left}
86
+ @media(max-width:768px){#fluxia-widget-root .fluxia-chatbox{width:calc(100vw - 32px);max-width:400px;height:calc(100vh - 140px);max-height:600px;bottom:10px;right:10px}#fluxia-widget-root .fluxia-bubble{bottom:20px;right:16px;width:56px;height:56px}}
87
+ @media(max-width:480px){#fluxia-widget-root .fluxia-chatbox{position:fixed;top:0;left:0;right:0;bottom:0;width:100%;height:100%;max-width:none;max-height:none;border-radius:0;transform-origin:bottom center}#fluxia-widget-root .fluxia-chatbox.fw-open{border-radius:0}#fluxia-widget-root .fluxia-header{border-radius:0}#fluxia-widget-root .fluxia-bubble{bottom:16px;right:16px;width:52px;height:52px}#fluxia-widget-root .fluxia-bubble svg{width:24px;height:24px}#fluxia-widget-root .fluxia-avatar{width:38px;height:38px;min-width:38px}#fluxia-widget-root .fluxia-title{font-size:14px}#fluxia-widget-root .fluxia-msg{max-width:88%;font-size:13px}#fluxia-widget-root .fluxia-input{font-size:14px}#fluxia-widget-root .fluxia-send{width:38px;height:38px;min-width:38px}}
88
+ `;
89
+ const injectStyles = () => {
90
+ if (document.getElementById(STYLE_ID)) return;
91
+ const el = document.createElement("style");
92
+ el.id = STYLE_ID;
93
+ el.textContent = CRITICAL_CSS;
94
+ document.head.appendChild(el);
95
+ };
96
+ const esc = (str) => {
97
+ const d = document.createElement("div");
98
+ d.textContent = str;
99
+ return d.innerHTML;
100
+ };
101
+ function widgetHTML({ botName, botAvatar }) {
102
+ const avatar = botAvatar ? `<img src="${esc(botAvatar)}" alt="Avatar" />` : "🤖";
103
+ return `
104
+ <button class="fluxia-bubble" aria-label="Abrir chat" title="Abrir chat">
105
+ <svg viewBox="0 0 24 24"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
106
+ </button>
107
+
108
+ <div class="fluxia-chatbox" role="dialog" aria-label="Chat">
109
+ <div class="fluxia-header">
110
+ <div class="fluxia-header-info">
111
+ <div class="fluxia-avatar">${avatar}</div>
112
+ <div class="fluxia-header-text">
113
+ <div class="fluxia-title">${botName}</div>
114
+ <div class="fluxia-status">
115
+ <span class="fluxia-status-dot"></span>
116
+ Online agora
117
+ </div>
118
+ </div>
119
+ </div>
120
+ <button class="fluxia-close" aria-label="Fechar chat" title="Fechar">
121
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
122
+ <line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
123
+ </svg>
124
+ </button>
125
+ </div>
126
+
127
+ <div class="fluxia-messages"></div>
128
+
129
+ <div class="fluxia-input-area">
130
+ <input class="fluxia-input" type="text"
131
+ placeholder="Pergunte sobre leads, métricas ou integrações"
132
+ autocomplete="off" />
133
+ <button class="fluxia-send" title="Enviar">
134
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"
135
+ stroke-linecap="round" stroke-linejoin="round">
136
+ <line x1="22" y1="2" x2="11" y2="13"/>
137
+ <polygon points="22 2 15 22 11 13 2 9 22 2"/>
138
+ </svg>
139
+ </button>
140
+ </div>
141
+
142
+ <div class="fluxia-powered">
143
+ Powered by <a href="https://rowsky.com.br/" target="_blank" rel="noopener">Rowsky</a>
144
+ </div>
145
+ </div>
146
+ `;
147
+ }
148
+ const renderWidget = async ({ config, token, api, visitorId, botId }) => {
149
+ injectStyles();
41
150
  const theme = config.theme || {};
42
- const primaryColor = theme.primaryColor || "#dc2626";
43
151
  const position = theme.position || "right";
44
152
  const botName = config.botName || config.name || "Assistente";
45
- const container = document.createElement("div");
46
- container.id = "fluxia-widget-root";
47
- container.className = "chatbot-scope fluxia-widget";
48
- container.dataset.position = position;
49
- container.style.setProperty("--fluxia-primary", primaryColor);
50
- container.innerHTML = getWidgetHTML({
51
- botName,
52
- initialMessage: config.initialMessage
53
- });
54
- document.body.appendChild(container);
55
- let isOpen = false;
56
- const bubble = container.querySelector("#fluxia-bubble");
57
- const chatBox = container.querySelector("#fluxia-chatbox");
58
- const closeBtn = container.querySelector("#fluxia-close");
59
- const input = container.querySelector("#fluxia-input");
60
- const sendBtn = container.querySelector("#fluxia-send");
61
- const messagesContainer = container.querySelector("#fluxia-messages");
153
+ const botAvatar = config.botAvatar || "";
154
+ const customCss = config.customCss || "";
155
+ const root = document.createElement("div");
156
+ root.id = "fluxia-widget-root";
157
+ root.dataset.position = position;
158
+ root.innerHTML = widgetHTML({ botName: esc(botName), botAvatar });
159
+ document.body.appendChild(root);
160
+ if (customCss && customCss.trim()) {
161
+ const s = document.createElement("style");
162
+ s.id = "fluxia-widget-custom";
163
+ s.textContent = customCss;
164
+ document.head.appendChild(s);
165
+ }
166
+ const bubble = root.querySelector(".fluxia-bubble");
167
+ const chatbox = root.querySelector(".fluxia-chatbox");
168
+ const closeBtn = root.querySelector(".fluxia-close");
169
+ const input = root.querySelector(".fluxia-input");
170
+ const sendBtn = root.querySelector(".fluxia-send");
171
+ const messages = root.querySelector(".fluxia-messages");
62
172
  if (config.initialMessage) {
63
- addMessage("assistant", config.initialMessage);
173
+ addMsg("assistant", config.initialMessage);
64
174
  }
65
- bubble.addEventListener("click", () => toggle(true));
66
- closeBtn.addEventListener("click", () => toggle(false));
67
- sendBtn.addEventListener("click", handleSend);
175
+ bubble.addEventListener("click", () => open());
176
+ closeBtn.addEventListener("click", () => close());
177
+ sendBtn.addEventListener("click", send);
68
178
  input.addEventListener("keydown", (e) => {
69
179
  if (e.key === "Enter" && !e.shiftKey) {
70
180
  e.preventDefault();
71
- handleSend();
181
+ send();
72
182
  }
73
183
  });
74
- function toggle(open) {
75
- isOpen = open;
76
- chatBox.style.display = isOpen ? "flex" : "none";
77
- bubble.style.display = isOpen ? "none" : "flex";
184
+ function open() {
185
+ bubble.classList.add("fw-hidden");
186
+ chatbox.classList.add("fw-open");
187
+ setTimeout(() => input.focus(), 350);
188
+ }
189
+ function close() {
190
+ chatbox.classList.remove("fw-open");
191
+ setTimeout(() => bubble.classList.remove("fw-hidden"), 300);
78
192
  }
79
- function addMessage(role, content) {
193
+ function addMsg(role, content) {
80
194
  const div = document.createElement("div");
81
195
  div.className = `fluxia-msg fluxia-msg-${role}`;
82
196
  div.textContent = content;
83
- messagesContainer.appendChild(div);
84
- messagesContainer.scrollTop = messagesContainer.scrollHeight;
197
+ messages.appendChild(div);
198
+ messages.scrollTop = messages.scrollHeight;
85
199
  }
86
- async function handleSend() {
200
+ async function send() {
87
201
  const text = input.value.trim();
88
202
  if (!text) return;
89
203
  input.value = "";
90
204
  input.disabled = true;
91
205
  sendBtn.disabled = true;
92
- addMessage("user", text);
206
+ addMsg("user", text);
207
+ const loader = document.createElement("div");
208
+ loader.className = "fluxia-msg fluxia-msg-assistant";
209
+ loader.innerHTML = '<div class="fluxia-typing"><div class="fluxia-typing-dot"></div><div class="fluxia-typing-dot"></div><div class="fluxia-typing-dot"></div></div>';
210
+ messages.appendChild(loader);
211
+ messages.scrollTop = messages.scrollHeight;
93
212
  try {
94
213
  const result = await api.sendMessage(token, text);
214
+ loader.remove();
95
215
  if (result.reply) {
96
- addMessage("assistant", result.reply.content);
216
+ addMsg("assistant", result.reply.content);
97
217
  }
98
218
  } catch (err) {
219
+ loader.remove();
99
220
  if (err.status === 401) {
100
- addMessage("system", "Sessão expirada. Recarregue a página.");
221
+ addMsg("system", "Sessão expirada. Recarregue a página.");
101
222
  } else {
102
- addMessage("system", "Erro ao enviar mensagem. Tente novamente.");
223
+ addMsg("system", "Erro ao enviar mensagem. Tente novamente.");
103
224
  }
104
225
  console.error("[Fluxia]", err);
105
226
  } finally {
@@ -109,47 +230,8 @@ const renderWidget = ({ config, token, api, visitorId, botId }) => {
109
230
  }
110
231
  }
111
232
  };
112
- function getWidgetHTML({ botName }) {
113
- return `
114
- <div id="fluxia-bubble" class="fluxia-bubble" aria-label="Abrir chat" role="button">
115
- 💬
116
- </div>
117
-
118
- <div id="fluxia-chatbox" class="fluxia-chatbox" role="dialog" aria-live="polite">
119
- <div class="fluxia-header">
120
- <div class="fluxia-header-info">
121
- <div class="fluxia-avatar">🤖</div>
122
- <div>
123
- <div class="fluxia-title">${botName}</div>
124
- <div class="fluxia-status">Online</div>
125
- </div>
126
- </div>
127
- <button id="fluxia-close" class="fluxia-close" aria-label="Fechar">✕</button>
128
- </div>
129
-
130
- <div id="fluxia-messages" class="fluxia-messages"></div>
131
-
132
- <div class="fluxia-input-area">
133
- <input id="fluxia-input" class="fluxia-input" type="text" placeholder="Digite sua mensagem..." />
134
- <button id="fluxia-send" class="fluxia-send">Enviar</button>
135
- </div>
136
- </div>
137
- `;
138
- }
139
- const cssText = '/* Estilos do widget Fluxia — injetados inline no bundle */\r\n\r\n.fluxia-widget {\r\n --fluxia-primary: #dc2626;\r\n --fluxia-radius: 16px;\r\n --fluxia-shadow: 0 8px 32px rgba(0, 0, 0, 0.18);\r\n --fluxia-text: #0f172a;\r\n --fluxia-muted: #64748b;\r\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;\r\n}\r\n\r\n.fluxia-widget * {\r\n box-sizing: border-box;\r\n margin: 0;\r\n padding: 0;\r\n}\r\n\r\n.fluxia-bubble {\r\n position: fixed;\r\n bottom: 20px;\r\n z-index: 99999;\r\n width: 56px;\r\n height: 56px;\r\n border-radius: 50%;\r\n background: var(--fluxia-primary);\r\n color: #fff;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n cursor: pointer;\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);\r\n font-size: 24px;\r\n transition: transform 0.2s;\r\n}\r\n\r\n.fluxia-bubble:hover {\r\n transform: scale(1.1);\r\n}\r\n\r\n.fluxia-chatbox {\r\n display: none;\r\n position: fixed;\r\n bottom: 90px;\r\n z-index: 99999;\r\n width: 370px;\r\n height: 520px;\r\n border-radius: var(--fluxia-radius);\r\n background: #fff;\r\n box-shadow: var(--fluxia-shadow);\r\n flex-direction: column;\r\n overflow: hidden;\r\n}\r\n\r\n.fluxia-widget[data-position="left"] .fluxia-bubble,\r\n.fluxia-widget[data-position="left"] .fluxia-chatbox {\r\n left: 20px;\r\n right: auto;\r\n}\r\n\r\n.fluxia-widget[data-position="right"] .fluxia-bubble,\r\n.fluxia-widget[data-position="right"] .fluxia-chatbox {\r\n right: 20px;\r\n left: auto;\r\n}\r\n\r\n.fluxia-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 14px 16px;\r\n background: var(--fluxia-primary);\r\n color: #fff;\r\n}\r\n\r\n.fluxia-header-info {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n}\r\n\r\n.fluxia-avatar {\r\n width: 32px;\r\n height: 32px;\r\n border-radius: 50%;\r\n background: rgba(255, 255, 255, 0.2);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n font-size: 16px;\r\n}\r\n\r\n.fluxia-title {\r\n font-weight: 600;\r\n font-size: 14px;\r\n}\r\n\r\n.fluxia-status {\r\n font-size: 11px;\r\n opacity: 0.8;\r\n}\r\n\r\n.fluxia-close {\r\n background: none;\r\n border: none;\r\n color: #fff;\r\n font-size: 20px;\r\n cursor: pointer;\r\n padding: 4px;\r\n}\r\n\r\n.fluxia-messages {\r\n flex: 1;\r\n overflow-y: auto;\r\n padding: 16px;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 8px;\r\n}\r\n\r\n.fluxia-input-area {\r\n padding: 12px;\r\n border-top: 1px solid #e5e7eb;\r\n display: flex;\r\n gap: 8px;\r\n}\r\n\r\n.fluxia-input {\r\n flex: 1;\r\n border: 1px solid #d1d5db;\r\n border-radius: 8px;\r\n padding: 8px 12px;\r\n font-size: 13px;\r\n outline: none;\r\n}\r\n\r\n.fluxia-send {\r\n background: var(--fluxia-primary);\r\n color: #fff;\r\n border: none;\r\n border-radius: 8px;\r\n padding: 8px 14px;\r\n cursor: pointer;\r\n font-size: 13px;\r\n font-weight: 600;\r\n}\r\n\r\n.fluxia-msg {\r\n max-width: 80%;\r\n padding: 10px 14px;\r\n border-radius: 12px;\r\n font-size: 13px;\r\n line-height: 1.5;\r\n word-wrap: break-word;\r\n}\r\n\r\n.fluxia-msg-user {\r\n align-self: flex-end;\r\n background: #f1f5f9;\r\n color: #1e293b;\r\n border-bottom-right-radius: 4px;\r\n}\r\n\r\n.fluxia-msg-assistant {\r\n align-self: flex-start;\r\n background: var(--fluxia-primary);\r\n color: #fff;\r\n border-bottom-left-radius: 4px;\r\n}\r\n\r\n.fluxia-msg-system {\r\n align-self: center;\r\n background: #fef3c7;\r\n color: #92400e;\r\n font-size: 12px;\r\n border-radius: 8px;\r\n text-align: center;\r\n}\r\n';
140
233
  const VISITOR_ID_KEY = "fluxia_visitor_id";
141
- const STYLE_TAG_ID = "fluxia-widget-styles";
142
- const injectStyles = () => {
143
- if (document.getElementById(STYLE_TAG_ID)) return;
144
- if (!cssText.trim()) {
145
- console.warn("[Fluxia] CSS nao carregado. Verifique o build.");
146
- return;
147
- }
148
- const style = document.createElement("style");
149
- style.id = STYLE_TAG_ID;
150
- style.textContent = cssText;
151
- document.head.appendChild(style);
152
- };
234
+ const scriptFromLoad = document.currentScript;
153
235
  const getVisitorId = () => {
154
236
  let id = null;
155
237
  try {
@@ -166,10 +248,10 @@ const getVisitorId = () => {
166
248
  return id;
167
249
  };
168
250
  const getScriptConfig = () => {
169
- const script = document.currentScript || document.querySelector("script[data-bot-id]");
251
+ const script = scriptFromLoad || document.currentScript || document.querySelector("script[data-client-id], script[data-bot-id]");
170
252
  if (!script) {
171
253
  console.error(
172
- "[Fluxia] Script tag não encontrada. Use data-bot-id e data-public-key."
254
+ "[Fluxia] Script tag não encontrada. Use data-client-id OU data-bot-id + data-public-key."
173
255
  );
174
256
  return null;
175
257
  }
@@ -193,7 +275,6 @@ const getScriptConfig = () => {
193
275
  const init = async () => {
194
276
  const config = getScriptConfig();
195
277
  if (!config) return;
196
- injectStyles();
197
278
  const visitorId = getVisitorId();
198
279
  const api = createWidgetAPI(config.apiBase);
199
280
  try {
@@ -225,7 +306,7 @@ const init = async () => {
225
306
  if (!botConfig) {
226
307
  botConfig = await api.getConfig(token);
227
308
  }
228
- renderWidget({
309
+ await renderWidget({
229
310
  config: botConfig,
230
311
  token,
231
312
  api,
@@ -1 +1 @@
1
- !function(n){"function"==typeof define&&define.amd?define(n):n()}(function(){"use strict";const n='/* Estilos do widget Fluxia — injetados inline no bundle */\r\n\r\n.fluxia-widget {\r\n --fluxia-primary: #dc2626;\r\n --fluxia-radius: 16px;\r\n --fluxia-shadow: 0 8px 32px rgba(0, 0, 0, 0.18);\r\n --fluxia-text: #0f172a;\r\n --fluxia-muted: #64748b;\r\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;\r\n}\r\n\r\n.fluxia-widget * {\r\n box-sizing: border-box;\r\n margin: 0;\r\n padding: 0;\r\n}\r\n\r\n.fluxia-bubble {\r\n position: fixed;\r\n bottom: 20px;\r\n z-index: 99999;\r\n width: 56px;\r\n height: 56px;\r\n border-radius: 50%;\r\n background: var(--fluxia-primary);\r\n color: #fff;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n cursor: pointer;\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);\r\n font-size: 24px;\r\n transition: transform 0.2s;\r\n}\r\n\r\n.fluxia-bubble:hover {\r\n transform: scale(1.1);\r\n}\r\n\r\n.fluxia-chatbox {\r\n display: none;\r\n position: fixed;\r\n bottom: 90px;\r\n z-index: 99999;\r\n width: 370px;\r\n height: 520px;\r\n border-radius: var(--fluxia-radius);\r\n background: #fff;\r\n box-shadow: var(--fluxia-shadow);\r\n flex-direction: column;\r\n overflow: hidden;\r\n}\r\n\r\n.fluxia-widget[data-position="left"] .fluxia-bubble,\r\n.fluxia-widget[data-position="left"] .fluxia-chatbox {\r\n left: 20px;\r\n right: auto;\r\n}\r\n\r\n.fluxia-widget[data-position="right"] .fluxia-bubble,\r\n.fluxia-widget[data-position="right"] .fluxia-chatbox {\r\n right: 20px;\r\n left: auto;\r\n}\r\n\r\n.fluxia-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 14px 16px;\r\n background: var(--fluxia-primary);\r\n color: #fff;\r\n}\r\n\r\n.fluxia-header-info {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n}\r\n\r\n.fluxia-avatar {\r\n width: 32px;\r\n height: 32px;\r\n border-radius: 50%;\r\n background: rgba(255, 255, 255, 0.2);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n font-size: 16px;\r\n}\r\n\r\n.fluxia-title {\r\n font-weight: 600;\r\n font-size: 14px;\r\n}\r\n\r\n.fluxia-status {\r\n font-size: 11px;\r\n opacity: 0.8;\r\n}\r\n\r\n.fluxia-close {\r\n background: none;\r\n border: none;\r\n color: #fff;\r\n font-size: 20px;\r\n cursor: pointer;\r\n padding: 4px;\r\n}\r\n\r\n.fluxia-messages {\r\n flex: 1;\r\n overflow-y: auto;\r\n padding: 16px;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 8px;\r\n}\r\n\r\n.fluxia-input-area {\r\n padding: 12px;\r\n border-top: 1px solid #e5e7eb;\r\n display: flex;\r\n gap: 8px;\r\n}\r\n\r\n.fluxia-input {\r\n flex: 1;\r\n border: 1px solid #d1d5db;\r\n border-radius: 8px;\r\n padding: 8px 12px;\r\n font-size: 13px;\r\n outline: none;\r\n}\r\n\r\n.fluxia-send {\r\n background: var(--fluxia-primary);\r\n color: #fff;\r\n border: none;\r\n border-radius: 8px;\r\n padding: 8px 14px;\r\n cursor: pointer;\r\n font-size: 13px;\r\n font-weight: 600;\r\n}\r\n\r\n.fluxia-msg {\r\n max-width: 80%;\r\n padding: 10px 14px;\r\n border-radius: 12px;\r\n font-size: 13px;\r\n line-height: 1.5;\r\n word-wrap: break-word;\r\n}\r\n\r\n.fluxia-msg-user {\r\n align-self: flex-end;\r\n background: #f1f5f9;\r\n color: #1e293b;\r\n border-bottom-right-radius: 4px;\r\n}\r\n\r\n.fluxia-msg-assistant {\r\n align-self: flex-start;\r\n background: var(--fluxia-primary);\r\n color: #fff;\r\n border-bottom-left-radius: 4px;\r\n}\r\n\r\n.fluxia-msg-system {\r\n align-self: center;\r\n background: #fef3c7;\r\n color: #92400e;\r\n font-size: 12px;\r\n border-radius: 8px;\r\n text-align: center;\r\n}\r\n',r="fluxia_visitor_id",e="fluxia-widget-styles",i=async()=>{const i=(()=>{const n=document.currentScript||document.querySelector("script[data-bot-id]");if(!n)return console.error("[Fluxia] Script tag não encontrada. Use data-bot-id e data-public-key."),null;const r=n.getAttribute("data-bot-id"),e=n.getAttribute("data-public-key"),i=n.getAttribute("data-client-id"),t=n.getAttribute("data-api-base")||"";return t&&(i||r&&e)?{botId:r?Number(r):null,publicKey:e||"",clientId:i||"",apiBase:t.replace(/\/$/,"")}:(console.error("[Fluxia] Atributos obrigatorios: data-api-base e (data-client-id OU data-bot-id + data-public-key)"),null)})();if(!i)return;(()=>{if(document.getElementById(e))return;if(!n.trim())return void console.warn("[Fluxia] CSS nao carregado. Verifique o build.");const r=document.createElement("style");r.id=e,r.textContent=n,document.head.appendChild(r)})();const t=(()=>{let n=null;try{n=localStorage.getItem(r)}catch{}if(!n){n="v_"+crypto.randomUUID();try{localStorage.setItem(r,n)}catch{}}return n})(),a=(n=>{const r=async(r,e,i=null,t=null)=>{const a={"Content-Type":"application/json"};t&&(a.Authorization=`Bearer ${t}`);const o={method:r,headers:a};i&&(o.body=JSON.stringify(i));const l=await fetch(`${n}${e}`,o);if(!l.ok){const n=await l.json().catch(()=>({})),r=new Error(n.error||`HTTP ${l.status}`);throw r.status=l.status,r.data=n,r}return l.json()};return{bootstrap:({clientId:n,visitorId:e})=>r("POST","/widget/bootstrap",{clientId:n,visitorId:e}),handshake:({botId:n,publicKey:e,visitorId:i})=>r("POST","/widget/handshake",{botId:n,publicKey:e,visitorId:i}),getConfig:n=>r("GET","/widget/config",null,n),sendMessage:(n,e)=>r("POST","/widget/message",{message:e},n),captureLead:(n,e)=>r("POST","/widget/lead",e,n)}})(i.apiBase);try{let n="",r=null;if(i.clientId){const e=await a.bootstrap({clientId:i.clientId,visitorId:t});if(!e||!e.token)return void console.error("[Fluxia] Bootstrap falhou. Widget nao sera renderizado.");n=e.token,r=e.config||null}else{const r=await a.handshake({botId:i.botId,publicKey:i.publicKey,visitorId:t});if(!r||!r.token)return void console.error("[Fluxia] Handshake falhou. Widget nao sera renderizado.");n=r.token}r||(r=await a.getConfig(n)),(({config:n,token:r,api:e,visitorId:i,botId:t})=>{const a=n.theme||{},o=a.primaryColor||"#dc2626",l=a.position||"right",s=n.botName||n.name||"Assistente",d=document.createElement("div");d.id="fluxia-widget-root",d.className="chatbot-scope fluxia-widget",d.dataset.position=l,d.style.setProperty("--fluxia-primary",o),d.innerHTML=function({botName:n}){return`\n <div id="fluxia-bubble" class="fluxia-bubble" aria-label="Abrir chat" role="button">\n 💬\n </div>\n\n <div id="fluxia-chatbox" class="fluxia-chatbox" role="dialog" aria-live="polite">\n <div class="fluxia-header">\n <div class="fluxia-header-info">\n <div class="fluxia-avatar">🤖</div>\n <div>\n <div class="fluxia-title">${n}</div>\n <div class="fluxia-status">Online</div>\n </div>\n </div>\n <button id="fluxia-close" class="fluxia-close" aria-label="Fechar">✕</button>\n </div>\n\n <div id="fluxia-messages" class="fluxia-messages"></div>\n\n <div class="fluxia-input-area">\n <input id="fluxia-input" class="fluxia-input" type="text" placeholder="Digite sua mensagem..." />\n <button id="fluxia-send" class="fluxia-send">Enviar</button>\n </div>\n </div>\n `}({botName:s,initialMessage:n.initialMessage}),document.body.appendChild(d);let u=!1;const c=d.querySelector("#fluxia-bubble"),f=d.querySelector("#fluxia-chatbox"),x=d.querySelector("#fluxia-close"),p=d.querySelector("#fluxia-input"),b=d.querySelector("#fluxia-send"),g=d.querySelector("#fluxia-messages");function m(n){u=n,f.style.display=u?"flex":"none",c.style.display=u?"none":"flex"}function y(n,r){const e=document.createElement("div");e.className=`fluxia-msg fluxia-msg-${n}`,e.textContent=r,g.appendChild(e),g.scrollTop=g.scrollHeight}async function h(){const n=p.value.trim();if(n){p.value="",p.disabled=!0,b.disabled=!0,y("user",n);try{const i=await e.sendMessage(r,n);i.reply&&y("assistant",i.reply.content)}catch(i){401===i.status?y("system","Sessão expirada. Recarregue a página."):y("system","Erro ao enviar mensagem. Tente novamente."),console.error("[Fluxia]",i)}finally{p.disabled=!1,b.disabled=!1,p.focus()}}}n.initialMessage&&y("assistant",n.initialMessage),c.addEventListener("click",()=>m(!0)),x.addEventListener("click",()=>m(!1)),b.addEventListener("click",h),p.addEventListener("keydown",n=>{"Enter"!==n.key||n.shiftKey||(n.preventDefault(),h())})})({config:r,token:n,api:a,visitorId:t,botId:i.botId||(null==r?void 0:r.botId)}),console.log("[Fluxia] Widget inicializado com sucesso.")}catch(o){console.error("[Fluxia] Erro na inicialização:",o.message||o)}};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",i):i()});
1
+ !function(t){"function"==typeof define&&define.amd?define(t):t()}(function(){"use strict";const t="fluxia-widget-styles",e=t=>{const e=document.createElement("div");return e.textContent=t,e.innerHTML};const i=async({config:i,token:a,api:o,visitorId:n,botId:r})=>{(()=>{if(document.getElementById(t))return;const e=document.createElement("style");e.id=t,e.textContent='\n#fluxia-widget-root{all:initial;font-family:"Inter",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;font-size:14px;line-height:1.5;color:#1f2937;--fw-header:#0f172a;--fw-white:#fff;--fw-green:#22c55e;--fw-red:#ef4444;--fw-red-dark:#dc2626;--fw-text:#1f2937;--fw-gray-100:#f3f4f6;--fw-gray-200:#e5e7eb;--fw-gray-300:#d1d5db;--fw-gray-bg:#fafbfc;--fw-radius:20px;--fw-shadow:0 20px 60px rgba(0,0,0,.25)}\n#fluxia-widget-root *,#fluxia-widget-root *::before,#fluxia-widget-root *::after{box-sizing:border-box;margin:0;padding:0}\n#fluxia-widget-root .fluxia-bubble{position:fixed;bottom:24px;right:24px;z-index:2147483646;width:60px;height:60px;border-radius:50%;border:none;background:linear-gradient(135deg,#ef4444,#dc2626);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:0 8px 24px rgba(239,68,68,.5),0 0 0 4px rgba(255,255,255,.25);transition:transform .3s cubic-bezier(.34,1.56,.64,1),box-shadow .3s,opacity .25s;opacity:1}\n#fluxia-widget-root .fluxia-bubble.fw-hidden{transform:scale(0);opacity:0;pointer-events:none}\n#fluxia-widget-root .fluxia-bubble svg{width:28px;height:28px;fill:#fff;stroke:none}\n#fluxia-widget-root .fluxia-chatbox{position:fixed;bottom:10px;right:10px;z-index:2147483647;width:400px;height:600px;max-height:calc(100vh - 120px);border-radius:var(--fw-radius);background:var(--fw-white);box-shadow:var(--fw-shadow);display:flex;flex-direction:column;overflow:hidden;transform-origin:bottom right;transform:scale(0) translateY(20px);opacity:0;pointer-events:none;transition:transform .35s cubic-bezier(.34,1.56,.64,1),opacity .25s}\n#fluxia-widget-root .fluxia-chatbox.fw-open{transform:scale(1) translateY(0);opacity:1;pointer-events:auto}\n#fluxia-widget-root .fluxia-header{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px 16px;background:var(--fw-header);color:var(--fw-white);flex-shrink:0;border-radius:var(--fw-radius) var(--fw-radius) 0 0}\n#fluxia-widget-root .fluxia-header-info{display:flex;align-items:center;gap:12px;flex:1;min-width:0}\n#fluxia-widget-root .fluxia-avatar{width:42px;height:42px;min-width:42px;border-radius:50%;background:rgba(255,255,255,.12);border:2px solid rgba(34,197,94,.5);display:flex;align-items:center;justify-content:center;font-size:20px;overflow:hidden;color:#fff}\n#fluxia-widget-root .fluxia-avatar img{width:100%;height:100%;object-fit:cover;border-radius:50%}\n#fluxia-widget-root .fluxia-header-text{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}\n#fluxia-widget-root .fluxia-title{font-weight:700;font-size:15px;color:var(--fw-white);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n#fluxia-widget-root .fluxia-status{font-size:12px;color:var(--fw-green);display:flex;align-items:center;gap:6px;font-weight:600}\n#fluxia-widget-root .fluxia-status-dot{width:7px;height:7px;border-radius:50%;background:var(--fw-green);display:inline-block;animation:fw-pulse 2s ease-in-out infinite}\n@keyframes fw-pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.4;transform:scale(1.3)}}\n#fluxia-widget-root .fluxia-close{width:34px;height:34px;display:flex;align-items:center;justify-content:center;background:rgba(255,255,255,.08);border:none;color:var(--fw-white);cursor:pointer;border-radius:8px;transition:background .2s}\n#fluxia-widget-root .fluxia-close:hover{background:rgba(255,255,255,.18)}\n#fluxia-widget-root .fluxia-close svg{width:16px;height:16px}\n#fluxia-widget-root .fluxia-messages{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:10px;background:var(--fw-white)}\n#fluxia-widget-root .fluxia-msg{max-width:82%;padding:10px 14px;font-size:13.5px;line-height:1.55;word-wrap:break-word;overflow-wrap:break-word;animation:fw-msgIn .3s ease-out}\n@keyframes fw-msgIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}\n#fluxia-widget-root .fluxia-msg-assistant{align-self:flex-start;background:var(--fw-gray-100);color:var(--fw-text);border-radius:16px 16px 16px 4px}\n#fluxia-widget-root .fluxia-msg-user{align-self:flex-end;background:var(--fw-header);color:var(--fw-white);border-radius:16px 16px 4px 16px}\n#fluxia-widget-root .fluxia-msg-system{align-self:center;background:#fef3c7;color:#92400e;font-size:12px;padding:8px 14px;border-radius:8px;text-align:center;max-width:90%;border:1px solid #fde68a}\n#fluxia-widget-root .fluxia-typing{display:flex;gap:5px;align-items:center;padding:4px 0}\n#fluxia-widget-root .fluxia-typing-dot{width:7px;height:7px;border-radius:50%;background:#94a3b8;animation:fw-bounce 1.4s infinite ease-in-out}\n#fluxia-widget-root .fluxia-typing-dot:nth-child(2){animation-delay:.16s}\n#fluxia-widget-root .fluxia-typing-dot:nth-child(3){animation-delay:.32s}\n@keyframes fw-bounce{0%,80%,100%{transform:scale(.7);opacity:.4}40%{transform:scale(1.1);opacity:1}}\n#fluxia-widget-root .fluxia-input-area{padding:12px 14px;background:var(--fw-white);border-top:1px solid var(--fw-gray-200);display:flex;align-items:center;gap:10px;flex-shrink:0}\n#fluxia-widget-root .fluxia-input{flex:1;border:1.5px solid var(--fw-gray-300);border-radius:24px;padding:10px 16px;font-size:13px;font-family:inherit;outline:none;color:var(--fw-text);background:var(--fw-gray-bg);transition:border-color .2s,box-shadow .2s}\n#fluxia-widget-root .fluxia-input::placeholder{color:#9ca3af}\n#fluxia-widget-root .fluxia-input:focus{border-color:var(--fw-header);background:var(--fw-white);box-shadow:0 0 0 3px rgba(15,23,42,.06)}\n#fluxia-widget-root .fluxia-input:disabled{opacity:.5;cursor:not-allowed}\n#fluxia-widget-root .fluxia-send{width:40px;height:40px;min-width:40px;border-radius:50%;background:var(--fw-red);color:var(--fw-white);border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background .2s,transform .2s;flex-shrink:0}\n#fluxia-widget-root .fluxia-send:hover{background:var(--fw-red-dark);transform:scale(1.08)}\n#fluxia-widget-root .fluxia-send:active{transform:scale(.92)}\n#fluxia-widget-root .fluxia-send:disabled{opacity:.4;cursor:not-allowed;transform:none}\n#fluxia-widget-root .fluxia-send svg{width:18px;height:18px}\n#fluxia-widget-root .fluxia-powered{text-align:center;padding:8px 0;font-size:11px;color:#9ca3af;background:var(--fw-white);border-top:1px solid var(--fw-gray-200);flex-shrink:0}\n#fluxia-widget-root .fluxia-powered a{color:#6b7280;text-decoration:none;font-weight:600}\n#fluxia-widget-root[data-position="left"] .fluxia-bubble{left:24px;right:auto}\n#fluxia-widget-root[data-position="left"] .fluxia-chatbox{left:24px;right:auto;transform-origin:bottom left}\n@media(max-width:768px){#fluxia-widget-root .fluxia-chatbox{width:calc(100vw - 32px);max-width:400px;height:calc(100vh - 140px);max-height:600px;bottom:10px;right:10px}#fluxia-widget-root .fluxia-bubble{bottom:20px;right:16px;width:56px;height:56px}}\n@media(max-width:480px){#fluxia-widget-root .fluxia-chatbox{position:fixed;top:0;left:0;right:0;bottom:0;width:100%;height:100%;max-width:none;max-height:none;border-radius:0;transform-origin:bottom center}#fluxia-widget-root .fluxia-chatbox.fw-open{border-radius:0}#fluxia-widget-root .fluxia-header{border-radius:0}#fluxia-widget-root .fluxia-bubble{bottom:16px;right:16px;width:52px;height:52px}#fluxia-widget-root .fluxia-bubble svg{width:24px;height:24px}#fluxia-widget-root .fluxia-avatar{width:38px;height:38px;min-width:38px}#fluxia-widget-root .fluxia-title{font-size:14px}#fluxia-widget-root .fluxia-msg{max-width:88%;font-size:13px}#fluxia-widget-root .fluxia-input{font-size:14px}#fluxia-widget-root .fluxia-send{width:38px;height:38px;min-width:38px}}\n',document.head.appendChild(e)})();const d=(i.theme||{}).position||"right",l=i.botName||i.name||"Assistente",s=i.botAvatar||"",f=i.customCss||"",u=document.createElement("div");if(u.id="fluxia-widget-root",u.dataset.position=d,u.innerHTML=function({botName:t,botAvatar:i}){return`\n <button class="fluxia-bubble" aria-label="Abrir chat" title="Abrir chat">\n <svg viewBox="0 0 24 24"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>\n </button>\n\n <div class="fluxia-chatbox" role="dialog" aria-label="Chat">\n <div class="fluxia-header">\n <div class="fluxia-header-info">\n <div class="fluxia-avatar">${i?`<img src="${e(i)}" alt="Avatar" />`:"🤖"}</div>\n <div class="fluxia-header-text">\n <div class="fluxia-title">${t}</div>\n <div class="fluxia-status">\n <span class="fluxia-status-dot"></span>\n Online agora\n </div>\n </div>\n </div>\n <button class="fluxia-close" aria-label="Fechar chat" title="Fechar">\n <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">\n <line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>\n </svg>\n </button>\n </div>\n\n <div class="fluxia-messages"></div>\n\n <div class="fluxia-input-area">\n <input class="fluxia-input" type="text"\n placeholder="Pergunte sobre leads, métricas ou integrações"\n autocomplete="off" />\n <button class="fluxia-send" title="Enviar">\n <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"\n stroke-linecap="round" stroke-linejoin="round">\n <line x1="22" y1="2" x2="11" y2="13"/>\n <polygon points="22 2 15 22 11 13 2 9 22 2"/>\n </svg>\n </button>\n </div>\n\n <div class="fluxia-powered">\n Powered by <a href="https://rowsky.com.br/" target="_blank" rel="noopener">Rowsky</a>\n </div>\n </div>\n `}({botName:e(l),botAvatar:s}),document.body.appendChild(u),f&&f.trim()){const t=document.createElement("style");t.id="fluxia-widget-custom",t.textContent=f,document.head.appendChild(t)}const x=u.querySelector(".fluxia-bubble"),c=u.querySelector(".fluxia-chatbox"),p=u.querySelector(".fluxia-close"),g=u.querySelector(".fluxia-input"),w=u.querySelector(".fluxia-send"),h=u.querySelector(".fluxia-messages");function b(t,e){const i=document.createElement("div");i.className=`fluxia-msg fluxia-msg-${t}`,i.textContent=e,h.appendChild(i),h.scrollTop=h.scrollHeight}async function m(){const t=g.value.trim();if(!t)return;g.value="",g.disabled=!0,w.disabled=!0,b("user",t);const e=document.createElement("div");e.className="fluxia-msg fluxia-msg-assistant",e.innerHTML='<div class="fluxia-typing"><div class="fluxia-typing-dot"></div><div class="fluxia-typing-dot"></div><div class="fluxia-typing-dot"></div></div>',h.appendChild(e),h.scrollTop=h.scrollHeight;try{const i=await o.sendMessage(a,t);e.remove(),i.reply&&b("assistant",i.reply.content)}catch(i){e.remove(),401===i.status?b("system","Sessão expirada. Recarregue a página."):b("system","Erro ao enviar mensagem. Tente novamente."),console.error("[Fluxia]",i)}finally{g.disabled=!1,w.disabled=!1,g.focus()}}i.initialMessage&&b("assistant",i.initialMessage),x.addEventListener("click",()=>(x.classList.add("fw-hidden"),c.classList.add("fw-open"),void setTimeout(()=>g.focus(),350))),p.addEventListener("click",()=>(c.classList.remove("fw-open"),void setTimeout(()=>x.classList.remove("fw-hidden"),300))),w.addEventListener("click",m),g.addEventListener("keydown",t=>{"Enter"!==t.key||t.shiftKey||(t.preventDefault(),m())})},a="fluxia_visitor_id",o=document.currentScript,n=async()=>{const t=(()=>{const t=o||document.currentScript||document.querySelector("script[data-client-id], script[data-bot-id]");if(!t)return console.error("[Fluxia] Script tag não encontrada. Use data-client-id OU data-bot-id + data-public-key."),null;const e=t.getAttribute("data-bot-id"),i=t.getAttribute("data-public-key"),a=t.getAttribute("data-client-id"),n=t.getAttribute("data-api-base")||"";return n&&(a||e&&i)?{botId:e?Number(e):null,publicKey:i||"",clientId:a||"",apiBase:n.replace(/\/$/,"")}:(console.error("[Fluxia] Atributos obrigatorios: data-api-base e (data-client-id OU data-bot-id + data-public-key)"),null)})();if(!t)return;const e=(()=>{let t=null;try{t=localStorage.getItem(a)}catch{}if(!t){t="v_"+crypto.randomUUID();try{localStorage.setItem(a,t)}catch{}}return t})(),n=(t=>{const e=async(e,i,a=null,o=null)=>{const n={"Content-Type":"application/json"};o&&(n.Authorization=`Bearer ${o}`);const r={method:e,headers:n};a&&(r.body=JSON.stringify(a));const d=await fetch(`${t}${i}`,r);if(!d.ok){const t=await d.json().catch(()=>({})),e=new Error(t.error||`HTTP ${d.status}`);throw e.status=d.status,e.data=t,e}return d.json()};return{bootstrap:({clientId:t,visitorId:i})=>e("POST","/widget/bootstrap",{clientId:t,visitorId:i}),handshake:({botId:t,publicKey:i,visitorId:a})=>e("POST","/widget/handshake",{botId:t,publicKey:i,visitorId:a}),getConfig:t=>e("GET","/widget/config",null,t),sendMessage:(t,i)=>e("POST","/widget/message",{message:i},t),captureLead:(t,i)=>e("POST","/widget/lead",i,t)}})(t.apiBase);try{let a="",o=null;if(t.clientId){const i=await n.bootstrap({clientId:t.clientId,visitorId:e});if(!i||!i.token)return void console.error("[Fluxia] Bootstrap falhou. Widget nao sera renderizado.");a=i.token,o=i.config||null}else{const i=await n.handshake({botId:t.botId,publicKey:t.publicKey,visitorId:e});if(!i||!i.token)return void console.error("[Fluxia] Handshake falhou. Widget nao sera renderizado.");a=i.token}o||(o=await n.getConfig(a)),await i({config:o,token:a,api:n,visitorId:e,botId:t.botId||(null==o?void 0:o.botId)}),console.log("[Fluxia] Widget inicializado com sucesso.")}catch(r){console.error("[Fluxia] Erro na inicialização:",r.message||r)}};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",n):n()});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rowsky-chatbot-widget",
3
- "version": "1.0.5",
3
+ "version": "1.0.8",
4
4
  "description": "Widget público do chatbot Fluxia para embed via script tag",
5
5
  "main": "dist/chatbot.umd.js",
6
6
  "module": "dist/chatbot.es.js",