@spilki/widget 1.0.34 → 1.0.36
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/bootstrap.es.js +385 -268
- package/dist/bootstrap.es.js.map +1 -1
- package/dist/bootstrap.umd.js +12 -9
- package/dist/bootstrap.umd.js.map +1 -1
- package/dist/core/state.d.ts +3 -5
- package/dist/core/state.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/types.d.ts +0 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/bubble.d.ts +3 -0
- package/dist/ui/bubble.d.ts.map +1 -1
- package/dist/ui/overlap.d.ts +42 -0
- package/dist/ui/overlap.d.ts.map +1 -0
- package/dist/ui/panel.d.ts +1 -0
- package/dist/ui/panel.d.ts.map +1 -1
- package/dist/widget.es.js +386 -269
- package/dist/widget.es.js.map +1 -1
- package/dist/widget.umd.js +12 -9
- package/dist/widget.umd.js.map +1 -1
- package/package.json +1 -1
package/dist/bootstrap.es.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const G = `
|
|
2
2
|
<style>
|
|
3
3
|
:host {
|
|
4
4
|
all: initial;
|
|
@@ -12,6 +12,9 @@ const R = `
|
|
|
12
12
|
:host([data-position="bottom-left"]) {
|
|
13
13
|
left: 24px;
|
|
14
14
|
}
|
|
15
|
+
:host([data-dimmed]) button {
|
|
16
|
+
opacity: 0.4;
|
|
17
|
+
}
|
|
15
18
|
button {
|
|
16
19
|
all: unset;
|
|
17
20
|
position: relative;
|
|
@@ -25,7 +28,7 @@ const R = `
|
|
|
25
28
|
background: var(--spilki-accent);
|
|
26
29
|
color: #fff;
|
|
27
30
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
|
|
28
|
-
transition: transform 0.18s ease, box-shadow 0.18s ease;
|
|
31
|
+
transition: transform 0.18s ease, box-shadow 0.18s ease, opacity 0.2s ease;
|
|
29
32
|
}
|
|
30
33
|
button:focus-visible {
|
|
31
34
|
outline: 2px solid #fff;
|
|
@@ -71,13 +74,13 @@ const R = `
|
|
|
71
74
|
<span class="badge" hidden aria-hidden="true">0</span>
|
|
72
75
|
</button>
|
|
73
76
|
`;
|
|
74
|
-
function
|
|
77
|
+
function V(o) {
|
|
75
78
|
const e = document.createElement("div");
|
|
76
|
-
e.setAttribute("part", "bubble-root"), e.setAttribute("data-position",
|
|
79
|
+
e.setAttribute("part", "bubble-root"), e.setAttribute("data-position", o.position), e.style.setProperty("--spilki-accent", o.color);
|
|
77
80
|
const t = e.attachShadow({ mode: "open" });
|
|
78
|
-
t.innerHTML =
|
|
81
|
+
t.innerHTML = G;
|
|
79
82
|
const s = t.querySelector("button"), i = t.querySelector(".badge");
|
|
80
|
-
return s.addEventListener("click", () =>
|
|
83
|
+
return s.addEventListener("click", () => o.onClick()), {
|
|
81
84
|
element: e,
|
|
82
85
|
mount() {
|
|
83
86
|
document.body.appendChild(e);
|
|
@@ -85,20 +88,29 @@ function K(r) {
|
|
|
85
88
|
destroy() {
|
|
86
89
|
e.remove();
|
|
87
90
|
},
|
|
88
|
-
setOpen(
|
|
89
|
-
s.setAttribute("aria-expanded", String(
|
|
91
|
+
setOpen(a) {
|
|
92
|
+
s.setAttribute("aria-expanded", String(a)), s.setAttribute("aria-label", a ? "Close chat" : "Open chat");
|
|
90
93
|
},
|
|
91
|
-
setBadge(
|
|
92
|
-
const
|
|
93
|
-
if (
|
|
94
|
-
i.toggleAttribute("hidden", !0), i.textContent = "0",
|
|
94
|
+
setBadge(a) {
|
|
95
|
+
const r = Math.max(0, a), l = s.getAttribute("aria-expanded") === "true";
|
|
96
|
+
if (r === 0) {
|
|
97
|
+
i.toggleAttribute("hidden", !0), i.textContent = "0", l || s.setAttribute("aria-label", "Open chat");
|
|
95
98
|
return;
|
|
96
99
|
}
|
|
97
|
-
i.toggleAttribute("hidden", !1), i.textContent =
|
|
100
|
+
i.toggleAttribute("hidden", !1), i.textContent = r > 99 ? "99+" : String(r), l || s.setAttribute("aria-label", `Open chat, ${r} unread`);
|
|
101
|
+
},
|
|
102
|
+
setDimmed(a) {
|
|
103
|
+
e.toggleAttribute("data-dimmed", a);
|
|
104
|
+
},
|
|
105
|
+
setPassthrough(a) {
|
|
106
|
+
e.style.pointerEvents = a ? "none" : "";
|
|
107
|
+
},
|
|
108
|
+
setPosition(a) {
|
|
109
|
+
e.setAttribute("data-position", a);
|
|
98
110
|
}
|
|
99
111
|
};
|
|
100
112
|
}
|
|
101
|
-
const
|
|
113
|
+
const J = "https://api.spilki.app", M = {
|
|
102
114
|
welcome: "Hi! I'm your assistant.",
|
|
103
115
|
placeholder: "Type a message…",
|
|
104
116
|
sendLabel: "Send",
|
|
@@ -109,57 +121,57 @@ const H = "https://api.spilki.app", I = {
|
|
|
109
121
|
offline: "Unable to connect. Please try again later.",
|
|
110
122
|
title: "Spilki Assistant"
|
|
111
123
|
}, w = {
|
|
112
|
-
apiBase:
|
|
124
|
+
apiBase: J,
|
|
113
125
|
position: "bottom-right",
|
|
114
126
|
theme: "auto",
|
|
115
127
|
color: "#6366f1",
|
|
116
|
-
welcome:
|
|
128
|
+
welcome: M.welcome,
|
|
117
129
|
persist: !0,
|
|
118
130
|
sound: !0,
|
|
119
|
-
i18n:
|
|
131
|
+
i18n: M
|
|
120
132
|
};
|
|
121
|
-
function
|
|
122
|
-
var t, s, i,
|
|
123
|
-
const e = { ...
|
|
133
|
+
function X(o) {
|
|
134
|
+
var t, s, i, n, a, r, l, p;
|
|
135
|
+
const e = { ...M, ...(t = o.i18n) != null ? t : {} };
|
|
124
136
|
return {
|
|
125
137
|
...w,
|
|
126
|
-
...
|
|
127
|
-
apiBase: (s =
|
|
138
|
+
...o,
|
|
139
|
+
apiBase: (s = o.apiBase) != null ? s : w.apiBase,
|
|
128
140
|
i18n: e,
|
|
129
|
-
welcome: (i =
|
|
130
|
-
position: (
|
|
131
|
-
theme: (
|
|
132
|
-
color: (
|
|
133
|
-
persist: (
|
|
134
|
-
sound: (
|
|
141
|
+
welcome: (i = o.welcome) != null ? i : e.welcome,
|
|
142
|
+
position: (n = o.position) != null ? n : w.position,
|
|
143
|
+
theme: (a = o.theme) != null ? a : w.theme,
|
|
144
|
+
color: (r = o.color) != null ? r : w.color,
|
|
145
|
+
persist: (l = o.persist) != null ? l : w.persist,
|
|
146
|
+
sound: (p = o.sound) != null ? p : w.sound
|
|
135
147
|
};
|
|
136
148
|
}
|
|
137
|
-
function
|
|
138
|
-
return typeof crypto != "undefined" && crypto.randomUUID ? crypto.randomUUID() : `${
|
|
149
|
+
function Z(o = "msg") {
|
|
150
|
+
return typeof crypto != "undefined" && crypto.randomUUID ? crypto.randomUUID() : `${o}-${Math.random().toString(16).slice(2)}`;
|
|
139
151
|
}
|
|
140
|
-
function
|
|
141
|
-
var
|
|
142
|
-
return (e = (
|
|
152
|
+
function Q() {
|
|
153
|
+
var o, e;
|
|
154
|
+
return (e = (o = window.matchMedia) == null ? void 0 : o.call(window, "(prefers-color-scheme: dark)").matches) != null ? e : !1;
|
|
143
155
|
}
|
|
144
|
-
function
|
|
145
|
-
return
|
|
156
|
+
function R(o) {
|
|
157
|
+
return o === "light" || o === "dark" ? o : Q() ? "dark" : "light";
|
|
146
158
|
}
|
|
147
|
-
function
|
|
148
|
-
return
|
|
159
|
+
function A(o, e = 30) {
|
|
160
|
+
return o.slice(-e);
|
|
149
161
|
}
|
|
150
|
-
function
|
|
151
|
-
if (!
|
|
162
|
+
function ee(o) {
|
|
163
|
+
if (!o || o.length === 0) return;
|
|
152
164
|
const e = window.location.origin;
|
|
153
|
-
|
|
154
|
-
`SpilkiWidget: current origin ${e} not in allowedOriginsHint: ${
|
|
165
|
+
o.includes(e) || console.warn(
|
|
166
|
+
`SpilkiWidget: current origin ${e} not in allowedOriginsHint: ${o.join(", ")}`
|
|
155
167
|
);
|
|
156
168
|
}
|
|
157
|
-
const
|
|
158
|
-
function
|
|
159
|
-
const e = new Date(
|
|
160
|
-
return
|
|
169
|
+
const te = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
170
|
+
function se(o) {
|
|
171
|
+
const e = new Date(o), t = /* @__PURE__ */ new Date(), s = (l) => String(l).padStart(2, "0"), i = `${s(e.getHours())}:${s(e.getMinutes())}`, n = new Date(t.getFullYear(), t.getMonth(), t.getDate()).getTime(), a = n - 864e5, r = new Date(e.getFullYear(), e.getMonth(), e.getDate()).getTime();
|
|
172
|
+
return r === n ? `Today at ${i}` : r === a ? `Yesterday at ${i}` : `${te[e.getMonth()]} ${e.getDate()}, ${i}`;
|
|
161
173
|
}
|
|
162
|
-
const
|
|
174
|
+
const ie = ':host{--spilki-bg-light: #ffffff;--spilki-bg-dark: #0f172a;--spilki-text-light: #0f172a;--spilki-text-dark: #f8fafc;--spilki-border-light: rgba(15, 23, 42, .1);--spilki-border-dark: rgba(148, 163, 184, .25);--spilki-muted-light: #64748b;--spilki-muted-dark: #94a3b8;--spilki-shadow: 0 10px 40px rgba(15, 23, 42, .2);--spilki-radius: 16px;--spilki-font: "Inter", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;color:inherit;font-family:var(--spilki-font)}.wrapper{position:relative;width:100%;height:100%;display:flex;flex-direction:column;background:var(--spilki-surface);color:var(--spilki-text);border-radius:var(--spilki-radius);box-shadow:var(--spilki-shadow);border:1px solid var(--spilki-border);overflow:hidden}header{display:flex;align-items:center;justify-content:space-between;padding:.75rem 1rem;background:var(--spilki-surface);border-bottom:1px solid var(--spilki-border)}header h1{font-size:1rem;margin:0;display:flex;align-items:center;gap:.5rem}header button.close{border:none;background:transparent;color:inherit;font-size:1.25rem;cursor:pointer}header button.close:focus-visible{outline:2px solid var(--spilki-accent);outline-offset:2px;border-radius:4px}header .status-dot{width:10px;height:10px;border-radius:999px;background:var(--spilki-accent)}.messages{flex:1;overflow-y:auto;padding:1rem;display:flex;flex-direction:column;gap:.75rem;scrollbar-width:thin;scrollbar-color:rgba(148,163,184,.3) transparent;scroll-behavior:smooth}.message{display:flex;flex-direction:column;gap:.15rem;max-width:85%;width:fit-content;line-height:1.4;word-wrap:break-word;overflow-wrap:anywhere;white-space:pre-wrap}.message.user{align-self:flex-end;align-items:flex-end}.message .bubble{padding:.6rem .8rem;border-radius:1rem;background:#6366f126}.message.user .bubble{background:var(--spilki-accent);color:#fff}.message.bot .bubble{background:#94a3b826}.msg-time{font-size:.7rem;color:var(--spilki-muted);margin-top:2px}.date-separator{display:flex;align-items:center;gap:.5rem;padding:.4rem 0;font-size:.72rem;color:var(--spilki-muted);white-space:nowrap}.date-separator:before,.date-separator:after{content:"";flex:1;height:1px;background:var(--spilki-border)}.scroll-bottom{position:absolute;right:1rem;bottom:88px;width:38px;height:38px;border:none;border-radius:999px;background:var(--spilki-accent);color:#fff;box-shadow:0 8px 20px #0f172a40;cursor:pointer;opacity:0;pointer-events:none;transform:translateY(4px);transition:opacity .18s ease,transform .18s ease;z-index:3}.scroll-bottom.visible{opacity:1;pointer-events:auto;transform:translateY(0)}.scroll-arrow{font-size:.8rem;line-height:1}.scroll-count{position:absolute;top:-5px;right:-5px;min-width:16px;height:16px;border-radius:999px;background:#ef4444;color:#fff;font-size:10px;line-height:16px;text-align:center;padding:0 4px}.suggested-replies{display:flex;flex-wrap:wrap;gap:.4rem;padding:.5rem 1rem;border-top:1px solid var(--spilki-border)}.suggested-chip{border:1px solid var(--spilki-accent);background:transparent;color:var(--spilki-accent);border-radius:999px;padding:.35rem .75rem;font-size:.8rem;font-family:inherit;cursor:pointer;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;transition:background .15s,color .15s}.suggested-chip:hover{background:var(--spilki-accent);color:#fff}.suggested-chip:focus-visible{outline:2px solid var(--spilki-accent);outline-offset:2px}.input-area{padding:.5rem .75rem}.input-wrap{display:flex;align-items:center;border:1px solid var(--spilki-border);border-radius:1.5rem;background:transparent;padding-left:0}.input-area textarea{flex:1;resize:none;min-height:2.4rem;max-height:6rem;border:0;border-radius:0;outline:0;background:transparent;box-shadow:none;-webkit-box-shadow:none;-webkit-appearance:none;appearance:none;padding:.55rem 0 .55rem 1rem;font-family:inherit;font-size:.95rem;color:var(--spilki-text);scrollbar-width:thin;scrollbar-color:rgba(148,163,184,.3) transparent}.input-actions{display:flex;align-items:center;gap:.25rem;padding:.25rem .35rem;flex-shrink:0}.input-actions button{width:32px;height:32px;display:grid;place-items:center;border:none;border-radius:50%;cursor:pointer;padding:0;transition:opacity .15s}.emoji-btn{background:#6366f126;color:var(--spilki-accent)}.emoji-btn:hover{background:#6366f140}.emoji-btn:focus-visible{outline:2px solid var(--spilki-accent);outline-offset:1px}.send-btn{background:var(--spilki-accent);color:#fff}.send-btn:hover{opacity:.85}.send-btn:focus-visible{outline:2px solid var(--spilki-accent);outline-offset:2px}.emoji-picker{position:absolute;right:1rem;bottom:80px;width:240px;max-height:180px;overflow-y:auto;display:none;grid-template-columns:repeat(10,minmax(0,1fr));gap:.25rem;padding:.5rem;background:var(--spilki-surface);border:1px solid var(--spilki-border);border-radius:12px;box-shadow:0 14px 30px #0f172a40;z-index:4}.emoji-option{width:100%;aspect-ratio:1;border:none;border-radius:8px;background:transparent;font-size:1rem;cursor:pointer}.emoji-option:hover,.emoji-option:focus-visible{background:#94a3b833}.typing{font-size:.75rem;color:var(--spilki-muted);padding:0 1rem .75rem}.typing:after{content:"";animation:dots 1.2s steps(4,end) infinite}@keyframes dots{0%{content:""}25%{content:"."}50%{content:".."}75%{content:"..."}}.offline{font-size:.8rem;padding:0 1rem;color:#f97316}:host([data-theme="dark"]){--spilki-surface: var(--spilki-bg-dark);--spilki-text: var(--spilki-text-dark);--spilki-border: var(--spilki-border-dark);--spilki-muted: var(--spilki-muted-dark)}:host([data-theme="dark"]) .messages,:host([data-theme="dark"]) .input-area textarea,:host([data-theme="dark"]) .emoji-picker{scrollbar-color:rgba(255,255,255,.2) transparent}:host([data-theme="light"]){--spilki-surface: var(--spilki-bg-light);--spilki-text: var(--spilki-text-light);--spilki-border: var(--spilki-border-light);--spilki-muted: var(--spilki-muted-light)}:host([data-theme="dark"]) .message .bubble{background:#94a3b81f}:host([data-theme="dark"]) .message.bot .bubble{background:#6366f126}:host([data-theme="dark"]) .input-area textarea{background:transparent}.messages::-webkit-scrollbar,.input-area textarea::-webkit-scrollbar,.emoji-picker::-webkit-scrollbar{width:6px}.messages::-webkit-scrollbar-track,.input-area textarea::-webkit-scrollbar-track,.emoji-picker::-webkit-scrollbar-track{background:transparent}.messages::-webkit-scrollbar-thumb,.input-area textarea::-webkit-scrollbar-thumb,.emoji-picker::-webkit-scrollbar-thumb{background:#94a3b84d;border-radius:999px}.messages::-webkit-scrollbar-thumb:hover,.input-area textarea::-webkit-scrollbar-thumb:hover,.emoji-picker::-webkit-scrollbar-thumb:hover{background:#94a3b880}:host([data-theme="dark"]) .messages::-webkit-scrollbar-thumb,:host([data-theme="dark"]) .input-area textarea::-webkit-scrollbar-thumb,:host([data-theme="dark"]) .emoji-picker::-webkit-scrollbar-thumb{background:#fff3}:host([data-theme="dark"]) .messages::-webkit-scrollbar-thumb:hover,:host([data-theme="dark"]) .input-area textarea::-webkit-scrollbar-thumb:hover,:host([data-theme="dark"]) .emoji-picker::-webkit-scrollbar-thumb:hover{background:#ffffff59}.conversation-separator{display:flex;align-items:center;gap:.5rem;padding:.5rem 0;cursor:pointer;user-select:none;font-size:.7rem;color:var(--spilki-muted);white-space:nowrap}.conversation-separator:before,.conversation-separator:after{content:"";flex:1;height:1px;background:var(--spilki-border)}.conversation-separator:hover{color:var(--spilki-text)}.conversation-separator:focus-visible{outline:2px solid var(--spilki-accent);outline-offset:2px;border-radius:4px}.conversation-history{display:none;flex-direction:column;gap:.5rem}.conversation-history.expanded{display:flex}', $ = 24 * 60 * 60 * 1e3, oe = 2 * 60 * 1e3, ne = 200, re = [
|
|
163
175
|
"😀",
|
|
164
176
|
"😂",
|
|
165
177
|
"🤣",
|
|
@@ -211,10 +223,10 @@ const J = ':host{--spilki-bg-light: #ffffff;--spilki-bg-dark: #0f172a;--spilki-t
|
|
|
211
223
|
"☕",
|
|
212
224
|
"🍕"
|
|
213
225
|
];
|
|
214
|
-
function
|
|
215
|
-
return
|
|
226
|
+
function S(o) {
|
|
227
|
+
return o.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
216
228
|
}
|
|
217
|
-
class
|
|
229
|
+
class ae {
|
|
218
230
|
constructor(e) {
|
|
219
231
|
this.options = e, this.relativeTimeFormat = new Intl.RelativeTimeFormat(void 0, {
|
|
220
232
|
numeric: "auto"
|
|
@@ -229,9 +241,9 @@ class ee {
|
|
|
229
241
|
day: "numeric",
|
|
230
242
|
year: "numeric"
|
|
231
243
|
}), this.renderedMessages = [], this.focusable = [], this.seenIds = /* @__PURE__ */ new Set(), this.lastTimelineMessage = null, this.scrollUnreadCount = 0, this.emojiPickerOpen = !1, this.open = !1, this.host = document.createElement("div"), this.host.setAttribute("part", "panel-root"), this.host.style.position = "fixed", this.host.style.bottom = "96px", this.host.style[e.position === "bottom-right" ? "right" : "left"] = "24px", this.host.style.width = "360px", this.host.style.maxWidth = "calc(100vw - 32px)", this.host.style.height = "520px", this.host.style.display = "none", this.host.style.zIndex = "2147483001", this.shadow = this.host.attachShadow({ mode: "open" });
|
|
232
|
-
const t =
|
|
244
|
+
const t = S(e.i18n.title), s = S(e.i18n.typing), i = S(e.i18n.offline), n = S(e.i18n.placeholder), a = S(e.i18n.sendLabel);
|
|
233
245
|
this.shadow.innerHTML = `
|
|
234
|
-
<style>${
|
|
246
|
+
<style>${ie}</style>
|
|
235
247
|
<div class="wrapper" role="dialog" aria-modal="true" aria-label="${t}">
|
|
236
248
|
<header>
|
|
237
249
|
<h1><span class="status-dot" aria-hidden="true"></span>${t}</h1>
|
|
@@ -248,7 +260,7 @@ class ee {
|
|
|
248
260
|
<div class="emoji-picker" aria-label="Emoji picker"></div>
|
|
249
261
|
<div class="input-area">
|
|
250
262
|
<div class="input-wrap">
|
|
251
|
-
<textarea rows="1" placeholder="${
|
|
263
|
+
<textarea rows="1" placeholder="${n}" aria-label="${n}"></textarea>
|
|
252
264
|
<div class="input-actions">
|
|
253
265
|
<button class="emoji-btn" type="button" aria-label="Insert emoji">
|
|
254
266
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
|
@@ -258,7 +270,7 @@ class ee {
|
|
|
258
270
|
<circle cx="15" cy="10" r="1" fill="currentColor"/>
|
|
259
271
|
</svg>
|
|
260
272
|
</button>
|
|
261
|
-
<button type="button" class="send-btn" aria-label="${
|
|
273
|
+
<button type="button" class="send-btn" aria-label="${a}">
|
|
262
274
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
|
263
275
|
<path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" fill="currentColor"/>
|
|
264
276
|
</svg>
|
|
@@ -267,36 +279,39 @@ class ee {
|
|
|
267
279
|
</div>
|
|
268
280
|
</div>
|
|
269
281
|
</div>
|
|
270
|
-
`, this.host.dataset.theme = e.theme, this.host.style.setProperty("--spilki-accent", e.color), this.messagesEl = this.shadow.querySelector(".messages"), this.typingEl = this.shadow.querySelector(".typing"), this.input = this.shadow.querySelector("textarea"), this.offlineEl = this.shadow.querySelector(".offline"), this.sendButton = this.shadow.querySelector(".send-btn"), this.emojiButton = this.shadow.querySelector(".emoji-btn"), this.emojiPickerEl = this.shadow.querySelector(".emoji-picker"), this.scrollBottomButton = this.shadow.querySelector(".scroll-bottom"), this.scrollBottomCountEl = this.shadow.querySelector(".scroll-count"), this.closeButton = this.shadow.querySelector("header .close"), this.suggestedRepliesEl = this.shadow.querySelector(".suggested-replies"), this.handleCloseClick = () => this.options.onClose(), this.handleSendClick = () => this.send(), this.handleInputKeydown = (
|
|
271
|
-
if (
|
|
272
|
-
|
|
273
|
-
else if (
|
|
282
|
+
`, this.host.dataset.theme = e.theme, this.host.style.setProperty("--spilki-accent", e.color), this.messagesEl = this.shadow.querySelector(".messages"), this.typingEl = this.shadow.querySelector(".typing"), this.input = this.shadow.querySelector("textarea"), this.offlineEl = this.shadow.querySelector(".offline"), this.sendButton = this.shadow.querySelector(".send-btn"), this.emojiButton = this.shadow.querySelector(".emoji-btn"), this.emojiPickerEl = this.shadow.querySelector(".emoji-picker"), this.scrollBottomButton = this.shadow.querySelector(".scroll-bottom"), this.scrollBottomCountEl = this.shadow.querySelector(".scroll-count"), this.closeButton = this.shadow.querySelector("header .close"), this.suggestedRepliesEl = this.shadow.querySelector(".suggested-replies"), this.handleCloseClick = () => this.options.onClose(), this.handleSendClick = () => this.send(), this.handleInputKeydown = (r) => {
|
|
283
|
+
if (r.key === "Enter" && !r.shiftKey)
|
|
284
|
+
r.preventDefault(), this.send();
|
|
285
|
+
else if (r.key === "Escape") {
|
|
274
286
|
if (this.emojiPickerOpen) {
|
|
275
|
-
|
|
287
|
+
r.stopPropagation(), this.closeEmojiPicker();
|
|
276
288
|
return;
|
|
277
289
|
}
|
|
278
290
|
this.options.onClose();
|
|
279
291
|
}
|
|
280
|
-
}, this.handleShadowKeydown = (
|
|
281
|
-
const
|
|
282
|
-
if (
|
|
292
|
+
}, this.handleShadowKeydown = (r) => {
|
|
293
|
+
const l = r;
|
|
294
|
+
if (l.key === "Escape") {
|
|
283
295
|
if (this.emojiPickerOpen) {
|
|
284
|
-
|
|
296
|
+
l.preventDefault(), this.closeEmojiPicker();
|
|
285
297
|
return;
|
|
286
298
|
}
|
|
287
299
|
this.options.onClose();
|
|
288
300
|
}
|
|
289
|
-
|
|
301
|
+
l.key === "Tab" && this.trapFocus(l);
|
|
290
302
|
}, this.handleFocusin = () => this.collectFocusable(), this.handleMessagesScroll = () => this.updateScrollBottomState(), this.handleScrollBottomClick = () => {
|
|
291
303
|
this.scrollToBottom(), this.resetScrollUnreadCount();
|
|
292
304
|
}, this.handleEmojiClick = () => {
|
|
293
305
|
this.toggleEmojiPicker();
|
|
294
|
-
}, this.handleDocumentPointerDown = (
|
|
306
|
+
}, this.handleDocumentPointerDown = (r) => {
|
|
295
307
|
if (!this.emojiPickerOpen) return;
|
|
296
|
-
const
|
|
297
|
-
|
|
308
|
+
const l = r.composedPath();
|
|
309
|
+
l.includes(this.emojiPickerEl) || l.includes(this.emojiButton) || this.closeEmojiPicker();
|
|
298
310
|
}, this.closeButton.addEventListener("click", this.handleCloseClick), this.sendButton.addEventListener("click", this.handleSendClick), this.emojiButton.addEventListener("click", this.handleEmojiClick), this.scrollBottomButton.addEventListener("click", this.handleScrollBottomClick), this.input.addEventListener("keydown", this.handleInputKeydown), this.messagesEl.addEventListener("scroll", this.handleMessagesScroll), this.shadow.addEventListener("keydown", this.handleShadowKeydown), this.shadow.addEventListener("focusin", this.handleFocusin), document.addEventListener("pointerdown", this.handleDocumentPointerDown, !0), this.renderEmojiPicker(), this.updateScrollBottomState(), this.collectFocusable();
|
|
299
311
|
}
|
|
312
|
+
get element() {
|
|
313
|
+
return this.host;
|
|
314
|
+
}
|
|
300
315
|
mount() {
|
|
301
316
|
document.body.appendChild(this.host);
|
|
302
317
|
}
|
|
@@ -328,9 +343,9 @@ class ee {
|
|
|
328
343
|
renderWithConversations(e, t) {
|
|
329
344
|
this.messagesEl.innerHTML = "", this.seenIds.clear(), this.renderedMessages.length = 0, this.lastTimelineMessage = null;
|
|
330
345
|
for (const s of e) {
|
|
331
|
-
s.messages.forEach((
|
|
332
|
-
const i = this.createHistoryContainer(s.messages),
|
|
333
|
-
this.messagesEl.appendChild(i), this.messagesEl.appendChild(
|
|
346
|
+
s.messages.forEach((r) => this.seenIds.add(r.id));
|
|
347
|
+
const i = this.createHistoryContainer(s.messages), n = s.messages[s.messages.length - 1].ts, a = this.createSeparatorElement(n, i);
|
|
348
|
+
this.messagesEl.appendChild(i), this.messagesEl.appendChild(a);
|
|
334
349
|
}
|
|
335
350
|
t.forEach((s) => {
|
|
336
351
|
this.seenIds.add(s.id), this.appendTimelineMessage(s);
|
|
@@ -395,17 +410,17 @@ class ee {
|
|
|
395
410
|
}
|
|
396
411
|
createSeparatorElement(e, t) {
|
|
397
412
|
const s = document.createElement("div");
|
|
398
|
-
s.className = "conversation-separator", s.setAttribute("role", "button"), s.setAttribute("tabindex", "0"), s.setAttribute("aria-expanded", "false"), s.setAttribute("aria-label", "Show previous conversation"), s.textContent =
|
|
413
|
+
s.className = "conversation-separator", s.setAttribute("role", "button"), s.setAttribute("tabindex", "0"), s.setAttribute("aria-expanded", "false"), s.setAttribute("aria-label", "Show previous conversation"), s.textContent = se(e);
|
|
399
414
|
const i = () => {
|
|
400
|
-
const
|
|
401
|
-
s.setAttribute("aria-expanded", String(
|
|
415
|
+
const n = t.classList.toggle("expanded");
|
|
416
|
+
s.setAttribute("aria-expanded", String(n)), s.setAttribute(
|
|
402
417
|
"aria-label",
|
|
403
|
-
|
|
418
|
+
n ? "Hide previous conversation" : "Show previous conversation"
|
|
404
419
|
);
|
|
405
420
|
};
|
|
406
|
-
return s.addEventListener("click", i), s.addEventListener("keydown", (
|
|
407
|
-
const
|
|
408
|
-
(
|
|
421
|
+
return s.addEventListener("click", i), s.addEventListener("keydown", (n) => {
|
|
422
|
+
const a = n;
|
|
423
|
+
(a.key === "Enter" || a.key === " ") && (a.preventDefault(), i());
|
|
409
424
|
}), s;
|
|
410
425
|
}
|
|
411
426
|
createHistoryContainer(e) {
|
|
@@ -414,8 +429,8 @@ class ee {
|
|
|
414
429
|
let s = null;
|
|
415
430
|
return e.forEach((i) => {
|
|
416
431
|
this.appendDateSeparatorIfNeeded(s, i, t);
|
|
417
|
-
const { item:
|
|
418
|
-
t.appendChild(
|
|
432
|
+
const { item: n } = this.createMessageElement(i);
|
|
433
|
+
t.appendChild(n), s = i;
|
|
419
434
|
}), t;
|
|
420
435
|
}
|
|
421
436
|
appendTimelineMessage(e) {
|
|
@@ -431,24 +446,24 @@ class ee {
|
|
|
431
446
|
}
|
|
432
447
|
updateTimestampVisibility() {
|
|
433
448
|
for (let e = 0; e < this.renderedMessages.length; e += 1) {
|
|
434
|
-
const t = this.renderedMessages[e], s = this.renderedMessages[e + 1], i = !!s && s.message.author === t.message.author && s.message.ts - t.message.ts <=
|
|
449
|
+
const t = this.renderedMessages[e], s = this.renderedMessages[e + 1], i = !!s && s.message.author === t.message.author && s.message.ts - t.message.ts <= oe && s.message.ts >= t.message.ts;
|
|
435
450
|
t.timeEl.toggleAttribute("hidden", i), t.timeEl.textContent = this.formatMessageTimestamp(t.message.ts);
|
|
436
451
|
}
|
|
437
452
|
}
|
|
438
453
|
formatMessageTimestamp(e) {
|
|
439
454
|
const s = Date.now() - e;
|
|
440
|
-
if (s <
|
|
455
|
+
if (s < $) {
|
|
441
456
|
const i = Math.max(1, Math.round(s / 6e4));
|
|
442
457
|
if (i < 60)
|
|
443
458
|
return this.relativeTimeFormat.format(-i, "minute");
|
|
444
|
-
const
|
|
445
|
-
return this.relativeTimeFormat.format(-
|
|
459
|
+
const n = Math.max(1, Math.round(i / 60));
|
|
460
|
+
return this.relativeTimeFormat.format(-n, "hour");
|
|
446
461
|
}
|
|
447
462
|
return this.absoluteTimeFormat.format(new Date(e));
|
|
448
463
|
}
|
|
449
464
|
formatDateSeparator(e) {
|
|
450
465
|
const t = new Date(e), s = this.startOfDay(Date.now()), i = this.startOfDay(e);
|
|
451
|
-
return i === s ? "Today" : i === s -
|
|
466
|
+
return i === s ? "Today" : i === s - $ ? "Yesterday" : this.dateSeparatorFormat.format(t);
|
|
452
467
|
}
|
|
453
468
|
isSameDay(e, t) {
|
|
454
469
|
return this.startOfDay(e) === this.startOfDay(t);
|
|
@@ -458,7 +473,7 @@ class ee {
|
|
|
458
473
|
return new Date(t.getFullYear(), t.getMonth(), t.getDate()).getTime();
|
|
459
474
|
}
|
|
460
475
|
isScrolledUp() {
|
|
461
|
-
return this.distanceFromBottom() >
|
|
476
|
+
return this.distanceFromBottom() > ne;
|
|
462
477
|
}
|
|
463
478
|
distanceFromBottom() {
|
|
464
479
|
return this.messagesEl.scrollHeight - this.messagesEl.scrollTop - this.messagesEl.clientHeight;
|
|
@@ -505,7 +520,7 @@ class ee {
|
|
|
505
520
|
this.emojiPickerOpen && (this.emojiPickerOpen = !1, this.emojiPickerEl.style.display = "none", this.emojiButton.setAttribute("aria-expanded", "false"), this.collectFocusable());
|
|
506
521
|
}
|
|
507
522
|
renderEmojiPicker() {
|
|
508
|
-
this.emojiPickerEl.replaceChildren(),
|
|
523
|
+
this.emojiPickerEl.replaceChildren(), re.forEach((e) => {
|
|
509
524
|
const t = document.createElement("button");
|
|
510
525
|
t.type = "button", t.className = "emoji-option", t.textContent = e, t.setAttribute("aria-label", `Insert ${e}`), t.addEventListener("click", () => {
|
|
511
526
|
this.insertEmojiAtCursor(e), this.closeEmojiPicker();
|
|
@@ -513,11 +528,11 @@ class ee {
|
|
|
513
528
|
});
|
|
514
529
|
}
|
|
515
530
|
insertEmojiAtCursor(e) {
|
|
516
|
-
var
|
|
517
|
-
const t = this.input.value, s = (
|
|
531
|
+
var a, r;
|
|
532
|
+
const t = this.input.value, s = (a = this.input.selectionStart) != null ? a : t.length, i = (r = this.input.selectionEnd) != null ? r : t.length;
|
|
518
533
|
this.input.value = `${t.slice(0, s)}${e}${t.slice(i)}`;
|
|
519
|
-
const
|
|
520
|
-
this.input.setSelectionRange(
|
|
534
|
+
const n = s + e.length;
|
|
535
|
+
this.input.setSelectionRange(n, n), this.input.dispatchEvent(new Event("input", { bubbles: !0 })), this.input.focus();
|
|
521
536
|
}
|
|
522
537
|
collectFocusable() {
|
|
523
538
|
const e = this.shadow.querySelectorAll(
|
|
@@ -533,8 +548,117 @@ class ee {
|
|
|
533
548
|
e.shiftKey && i === t ? (e.preventDefault(), s.focus()) : !e.shiftKey && i === s && (e.preventDefault(), t.focus());
|
|
534
549
|
}
|
|
535
550
|
}
|
|
536
|
-
|
|
537
|
-
|
|
551
|
+
function le(o) {
|
|
552
|
+
if (!(o instanceof HTMLElement) || o.hasAttribute("disabled") || o.getAttribute("aria-disabled") === "true" || o.hasAttribute("inert"))
|
|
553
|
+
return !1;
|
|
554
|
+
const e = getComputedStyle(o);
|
|
555
|
+
if (e.display === "none" || e.visibility === "hidden" || e.pointerEvents === "none")
|
|
556
|
+
return !1;
|
|
557
|
+
const t = o.tagName;
|
|
558
|
+
if (t === "BUTTON" || t === "SELECT" || t === "TEXTAREA" || t === "A" && o.hasAttribute("href") || t === "INPUT" && o.type !== "hidden" || t === "IFRAME") return !0;
|
|
559
|
+
const s = o.getAttribute("role");
|
|
560
|
+
if (s === "button" || s === "link" || o.getAttribute("contenteditable") === "true") return !0;
|
|
561
|
+
const i = o.getAttribute("tabindex");
|
|
562
|
+
return i !== null && i !== "-1";
|
|
563
|
+
}
|
|
564
|
+
function K(o, e, t) {
|
|
565
|
+
const s = document.elementsFromPoint(o, e);
|
|
566
|
+
for (const i of s) {
|
|
567
|
+
if (t.has(i)) continue;
|
|
568
|
+
let n = !1;
|
|
569
|
+
for (const a of t)
|
|
570
|
+
if (a.contains(i)) {
|
|
571
|
+
n = !0;
|
|
572
|
+
break;
|
|
573
|
+
}
|
|
574
|
+
if (!n && le(i))
|
|
575
|
+
return !0;
|
|
576
|
+
}
|
|
577
|
+
return !1;
|
|
578
|
+
}
|
|
579
|
+
function N(o, e) {
|
|
580
|
+
const t = [
|
|
581
|
+
[o.x + o.width / 2, o.y + o.height / 2],
|
|
582
|
+
[o.x + o.width / 2, o.y + 4],
|
|
583
|
+
[o.x + o.width / 2, o.y + o.height - 4],
|
|
584
|
+
[o.x + 4, o.y + o.height / 2],
|
|
585
|
+
[o.x + o.width - 4, o.y + o.height / 2]
|
|
586
|
+
];
|
|
587
|
+
for (const [s, i] of t)
|
|
588
|
+
if (K(s, i, e)) return !0;
|
|
589
|
+
return !1;
|
|
590
|
+
}
|
|
591
|
+
function F() {
|
|
592
|
+
var o, e;
|
|
593
|
+
return (e = (o = window.matchMedia) == null ? void 0 : o.call(window, "(pointer: coarse)").matches) != null ? e : !1;
|
|
594
|
+
}
|
|
595
|
+
function ce(o) {
|
|
596
|
+
return o === "bottom-right" ? "bottom-left" : "bottom-right";
|
|
597
|
+
}
|
|
598
|
+
class he {
|
|
599
|
+
constructor(e) {
|
|
600
|
+
this.rafId = 0, this.pendingX = 0, this.pendingY = 0, this.pendingUpdate = !1, this.passthrough = !1, this.cachedRect = null, this.bubble = e.bubble, this.widgetHosts = e.widgetHosts, this.currentPosition = e.position, this.handlePointerMove = (t) => this.onPointerMove(t), this.handlePointerUp = () => this.exitPassthrough(), this.handleScroll = () => this.onLayoutChange(), this.handleResize = () => this.onLayoutChange(), window.addEventListener("scroll", this.handleScroll, { passive: !0 }), window.addEventListener("resize", this.handleResize, { passive: !0 }), F() ? this.scheduleAutoDockCheck() : (document.addEventListener("pointermove", this.handlePointerMove, {
|
|
601
|
+
passive: !0
|
|
602
|
+
}), document.addEventListener("pointerup", this.handlePointerUp, {
|
|
603
|
+
passive: !0
|
|
604
|
+
})), requestAnimationFrame(() => this.onLayoutChange());
|
|
605
|
+
}
|
|
606
|
+
destroy() {
|
|
607
|
+
document.removeEventListener("pointermove", this.handlePointerMove), document.removeEventListener("pointerup", this.handlePointerUp), window.removeEventListener("scroll", this.handleScroll), window.removeEventListener("resize", this.handleResize), this.rafId && cancelAnimationFrame(this.rafId), this.exitPassthrough();
|
|
608
|
+
}
|
|
609
|
+
onPointerMove(e) {
|
|
610
|
+
this.pendingX = e.clientX, this.pendingY = e.clientY, this.pendingUpdate || (this.pendingUpdate = !0, this.rafId = requestAnimationFrame(() => this.tick()));
|
|
611
|
+
}
|
|
612
|
+
tick() {
|
|
613
|
+
this.pendingUpdate = !1;
|
|
614
|
+
const e = this.getBubbleRect(), t = this.pendingX, s = this.pendingY;
|
|
615
|
+
if (!(t >= e.left && t <= e.right && s >= e.top && s <= e.bottom)) {
|
|
616
|
+
this.passthrough && this.exitPassthrough();
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
const n = this.bubble.element, a = n.style.pointerEvents;
|
|
620
|
+
n.style.pointerEvents = "none";
|
|
621
|
+
const r = K(t, s, this.widgetHosts);
|
|
622
|
+
n.style.pointerEvents = a, r && !this.passthrough ? this.enterPassthrough() : !r && this.passthrough && this.exitPassthrough();
|
|
623
|
+
}
|
|
624
|
+
enterPassthrough() {
|
|
625
|
+
this.passthrough = !0, this.bubble.setDimmed(!0), this.bubble.setPassthrough(!0);
|
|
626
|
+
}
|
|
627
|
+
exitPassthrough() {
|
|
628
|
+
this.passthrough && (this.passthrough = !1, this.bubble.setDimmed(!1), this.bubble.setPassthrough(!1));
|
|
629
|
+
}
|
|
630
|
+
scheduleAutoDockCheck() {
|
|
631
|
+
requestAnimationFrame(() => this.autoDockIfNeeded());
|
|
632
|
+
}
|
|
633
|
+
autoDockIfNeeded() {
|
|
634
|
+
this.invalidateRect();
|
|
635
|
+
const e = this.getBubbleRect(), t = this.bubble.element, s = t.style.pointerEvents;
|
|
636
|
+
t.style.pointerEvents = "none";
|
|
637
|
+
const i = N(e, this.widgetHosts);
|
|
638
|
+
if (t.style.pointerEvents = s, !i) return;
|
|
639
|
+
const n = ce(this.currentPosition);
|
|
640
|
+
this.currentPosition = n, this.bubble.setPosition(n), this.invalidateRect(), requestAnimationFrame(() => {
|
|
641
|
+
const a = this.getBubbleRect(), r = this.bubble.element, l = r.style.pointerEvents;
|
|
642
|
+
r.style.pointerEvents = "none";
|
|
643
|
+
const p = N(
|
|
644
|
+
a,
|
|
645
|
+
this.widgetHosts
|
|
646
|
+
);
|
|
647
|
+
r.style.pointerEvents = l, p && this.bubble.setDimmed(!0);
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
onLayoutChange() {
|
|
651
|
+
this.invalidateRect(), F() && this.autoDockIfNeeded();
|
|
652
|
+
}
|
|
653
|
+
getBubbleRect() {
|
|
654
|
+
return this.cachedRect || (this.cachedRect = this.bubble.element.getBoundingClientRect()), this.cachedRect;
|
|
655
|
+
}
|
|
656
|
+
invalidateRect() {
|
|
657
|
+
this.cachedRect = null;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
const v = 1500, W = 8e3;
|
|
661
|
+
class de {
|
|
538
662
|
constructor(e, t) {
|
|
539
663
|
this.sessionId = null, this.currentKind = null, this.stopped = !1, this.backoff = v, this.connectPromise = null, this.options = e, this.handlers = t;
|
|
540
664
|
}
|
|
@@ -545,8 +669,8 @@ class te {
|
|
|
545
669
|
const t = {};
|
|
546
670
|
for (const [s, i] of Object.entries(e))
|
|
547
671
|
if (typeof i == "string") {
|
|
548
|
-
const
|
|
549
|
-
|
|
672
|
+
const n = i.trim();
|
|
673
|
+
n && (t[s] = n);
|
|
550
674
|
}
|
|
551
675
|
this.user = t, this.sessionId && this.sendIdentify().catch(
|
|
552
676
|
(s) => this.handlers.onError(s)
|
|
@@ -585,9 +709,9 @@ class te {
|
|
|
585
709
|
}
|
|
586
710
|
}
|
|
587
711
|
async doConnect() {
|
|
588
|
-
var
|
|
712
|
+
var a, r;
|
|
589
713
|
this.stopped = !1;
|
|
590
|
-
const e = `${this.options.apiBase.replace(/\/$/, "")}/widget/session`, t = (
|
|
714
|
+
const e = `${this.options.apiBase.replace(/\/$/, "")}/widget/session`, t = (r = (a = this.sessionId) != null ? a : this.options.sessionId) != null ? r : void 0, s = {
|
|
591
715
|
organisationId: this.options.org,
|
|
592
716
|
sessionId: t,
|
|
593
717
|
userAgent: typeof navigator != "undefined" ? navigator.userAgent : "",
|
|
@@ -604,16 +728,16 @@ class te {
|
|
|
604
728
|
});
|
|
605
729
|
if (!i.ok)
|
|
606
730
|
throw new Error(`SpilkiWidget: connect failed (${i.status})`);
|
|
607
|
-
const
|
|
608
|
-
return this.sessionId =
|
|
731
|
+
const n = await i.json();
|
|
732
|
+
return this.sessionId = n.sessionId, this.options.sessionId = n.sessionId, this.backoff = v, await this.startTransport(n), n;
|
|
609
733
|
}
|
|
610
734
|
async send(e, t) {
|
|
611
|
-
var
|
|
735
|
+
var a, r, l;
|
|
612
736
|
const s = {
|
|
613
|
-
sessionId: (
|
|
737
|
+
sessionId: (r = (a = this.sessionId) != null ? a : this.options.sessionId) != null ? r : "",
|
|
614
738
|
text: e,
|
|
615
739
|
...t ? { messageId: t } : {},
|
|
616
|
-
...(
|
|
740
|
+
...(l = this.user) != null && l.userId ? { userId: this.user.userId } : {}
|
|
617
741
|
};
|
|
618
742
|
if (!s.sessionId)
|
|
619
743
|
throw new Error("SpilkiWidget: missing session id");
|
|
@@ -621,7 +745,7 @@ class te {
|
|
|
621
745
|
this.ws.send(JSON.stringify({ type: "message", payload: s }));
|
|
622
746
|
return;
|
|
623
747
|
}
|
|
624
|
-
const i = `${this.options.apiBase.replace(/\/$/, "")}/widget/message`,
|
|
748
|
+
const i = `${this.options.apiBase.replace(/\/$/, "")}/widget/message`, n = await fetch(i, {
|
|
625
749
|
method: "POST",
|
|
626
750
|
headers: {
|
|
627
751
|
"Content-Type": "application/json",
|
|
@@ -629,8 +753,8 @@ class te {
|
|
|
629
753
|
},
|
|
630
754
|
body: JSON.stringify(s)
|
|
631
755
|
});
|
|
632
|
-
if (!
|
|
633
|
-
throw new Error(`SpilkiWidget: send failed (${
|
|
756
|
+
if (!n.ok)
|
|
757
|
+
throw new Error(`SpilkiWidget: send failed (${n.status})`);
|
|
634
758
|
}
|
|
635
759
|
// #1: accept resetBackoff param; #8 #9: clear retryTimer
|
|
636
760
|
stop(e = !0) {
|
|
@@ -660,7 +784,7 @@ class te {
|
|
|
660
784
|
return;
|
|
661
785
|
}
|
|
662
786
|
this.currentKind = "ws", this.handlers.onOpen("ws"), this.backoff = v, t();
|
|
663
|
-
}, this.wsOnMessage = (
|
|
787
|
+
}, this.wsOnMessage = (n) => this.handleIncoming(n.data), this.wsOnClose = () => {
|
|
664
788
|
this.stopped || this.retryFallback("ws");
|
|
665
789
|
}, this.wsOnError = () => {
|
|
666
790
|
this.handlers.onError(new Error("SpilkiWidget: websocket error")), i.readyState !== WebSocket.OPEN && s(new Error("WebSocket failed"));
|
|
@@ -680,8 +804,8 @@ class te {
|
|
|
680
804
|
"X-Authorization": `Bearer ${this.options.accessToken}`
|
|
681
805
|
},
|
|
682
806
|
signal: i.signal
|
|
683
|
-
}).then((
|
|
684
|
-
if (!
|
|
807
|
+
}).then((n) => {
|
|
808
|
+
if (!n.ok || !n.body) {
|
|
685
809
|
s(new Error("SSE failed"));
|
|
686
810
|
return;
|
|
687
811
|
}
|
|
@@ -690,32 +814,32 @@ class te {
|
|
|
690
814
|
return;
|
|
691
815
|
}
|
|
692
816
|
this.currentKind = "sse", this.handlers.onOpen("sse"), this.backoff = v, t();
|
|
693
|
-
const
|
|
694
|
-
let
|
|
695
|
-
const
|
|
696
|
-
|
|
697
|
-
var
|
|
817
|
+
const a = n.body.getReader(), r = new TextDecoder();
|
|
818
|
+
let l = "";
|
|
819
|
+
const p = () => {
|
|
820
|
+
a.read().then(({ done: u, value: h }) => {
|
|
821
|
+
var y;
|
|
698
822
|
if (u || this.stopped) {
|
|
699
823
|
this.stopped || (this.handlers.onError(new Error("SpilkiWidget: SSE stream ended")), this.retryFallback("sse"));
|
|
700
824
|
return;
|
|
701
825
|
}
|
|
702
|
-
|
|
703
|
-
const
|
|
826
|
+
l += r.decode(h, { stream: !0 });
|
|
827
|
+
const d = l.split(`
|
|
704
828
|
|
|
705
829
|
`);
|
|
706
|
-
|
|
707
|
-
for (const f of
|
|
708
|
-
for (const
|
|
830
|
+
l = (y = d.pop()) != null ? y : "";
|
|
831
|
+
for (const f of d)
|
|
832
|
+
for (const g of f.split(`
|
|
709
833
|
`))
|
|
710
|
-
|
|
711
|
-
|
|
834
|
+
g.startsWith("data:") && this.handleIncoming(g.slice(5).trim());
|
|
835
|
+
p();
|
|
712
836
|
}).catch((u) => {
|
|
713
837
|
i.signal.aborted || (this.handlers.onError(u), this.stopped || this.retryFallback("sse"));
|
|
714
838
|
});
|
|
715
839
|
};
|
|
716
|
-
|
|
717
|
-
}).catch((
|
|
718
|
-
i.signal.aborted || s(
|
|
840
|
+
p();
|
|
841
|
+
}).catch((n) => {
|
|
842
|
+
i.signal.aborted || s(n);
|
|
719
843
|
});
|
|
720
844
|
});
|
|
721
845
|
}
|
|
@@ -732,9 +856,9 @@ class te {
|
|
|
732
856
|
});
|
|
733
857
|
if (!s.ok) throw new Error(`Poll failed ${s.status}`);
|
|
734
858
|
const i = await s.json();
|
|
735
|
-
|
|
859
|
+
A(i).forEach((n) => this.handlers.onMessage(n)), this.backoff = v;
|
|
736
860
|
} catch (s) {
|
|
737
|
-
this.handlers.onError(s), this.backoff = Math.min(this.backoff * 1.5,
|
|
861
|
+
this.handlers.onError(s), this.backoff = Math.min(this.backoff * 1.5, W);
|
|
738
862
|
} finally {
|
|
739
863
|
this.stopped || (this.pollTimer = window.setTimeout(t, this.backoff));
|
|
740
864
|
}
|
|
@@ -743,7 +867,7 @@ class te {
|
|
|
743
867
|
}
|
|
744
868
|
// #1: preserve backoff by calling stop(false); #8: check stopped before reconnect
|
|
745
869
|
retryFallback(e) {
|
|
746
|
-
this.stopped || (this.stop(!1), this.backoff = Math.min(this.backoff * 1.5,
|
|
870
|
+
this.stopped || (this.stop(!1), this.backoff = Math.min(this.backoff * 1.5, W), this.retryTimer = window.setTimeout(() => {
|
|
747
871
|
this.stopped || (this.handlers.onError(new Error(`SpilkiWidget: retrying after ${e}`)), this.connect().catch((t) => this.handlers.onError(t)));
|
|
748
872
|
}, this.backoff));
|
|
749
873
|
}
|
|
@@ -763,22 +887,22 @@ class te {
|
|
|
763
887
|
dispatchIncoming(e) {
|
|
764
888
|
var t;
|
|
765
889
|
if ("type" in e) {
|
|
766
|
-
e.type === "message" ? this.handlers.onMessage(e.payload) : e.type === "typing" ? this.handlers.onTyping(!!((t = e.payload) != null && t.active)) : e.type === "AGENT_EVENT" &&
|
|
890
|
+
e.type === "message" ? this.handlers.onMessage(e.payload) : e.type === "typing" ? this.handlers.onTyping(!!((t = e.payload) != null && t.active)) : e.type === "AGENT_EVENT" && pe(e.payload) && this.handlers.onAgentEvent(e.payload);
|
|
767
891
|
return;
|
|
768
892
|
}
|
|
769
893
|
this.handlers.onMessage(e);
|
|
770
894
|
}
|
|
771
895
|
}
|
|
772
|
-
const
|
|
773
|
-
function
|
|
774
|
-
if (typeof
|
|
775
|
-
const e =
|
|
776
|
-
return
|
|
896
|
+
const ue = /* @__PURE__ */ new Set(["TYPING", "THINKING", "SEARCHING", "EXECUTING_TOOL"]);
|
|
897
|
+
function pe(o) {
|
|
898
|
+
if (typeof o != "object" || o === null) return !1;
|
|
899
|
+
const e = o;
|
|
900
|
+
return ue.has(e.eventType);
|
|
777
901
|
}
|
|
778
|
-
const
|
|
779
|
-
class
|
|
902
|
+
const H = 30 * 60 * 1e3, ge = 3e4, O = 30;
|
|
903
|
+
class me {
|
|
780
904
|
constructor(e, t) {
|
|
781
|
-
this.org = e, this.listeners = /* @__PURE__ */ new Set(), this.activityTimer = null, this.
|
|
905
|
+
this.org = e, this.listeners = /* @__PURE__ */ new Set(), this.activityTimer = null, this.state = {
|
|
782
906
|
isOpen: !1,
|
|
783
907
|
agentActivity: null,
|
|
784
908
|
isConnected: !1,
|
|
@@ -802,27 +926,16 @@ class oe {
|
|
|
802
926
|
close() {
|
|
803
927
|
this.state.isOpen && (this.state.isOpen = !1, this.emit());
|
|
804
928
|
}
|
|
805
|
-
handleAgentEvent(e
|
|
806
|
-
|
|
929
|
+
handleAgentEvent(e) {
|
|
930
|
+
this.activityTimer && (clearTimeout(this.activityTimer), this.activityTimer = null), this.activityTimer = setTimeout(() => {
|
|
931
|
+
this.state.agentActivity = null, this.activityTimer = null, this.emit();
|
|
932
|
+
}, ge), this.state.agentActivity !== e && (this.state.agentActivity = e, this.emit());
|
|
807
933
|
}
|
|
808
|
-
|
|
809
|
-
this.
|
|
810
|
-
}
|
|
811
|
-
updateDisplayedActivity() {
|
|
812
|
-
this.activityTimer && (clearTimeout(this.activityTimer), this.activityTimer = null), this.activeEvents.size > 0 && (this.activityTimer = setTimeout(() => {
|
|
813
|
-
this.activeEvents.clear(), this.state.agentActivity = null, this.activityTimer = null, this.emit();
|
|
814
|
-
}, re));
|
|
815
|
-
const e = this.resolveTopActivity();
|
|
816
|
-
this.state.agentActivity !== e && (this.state.agentActivity = e, this.emit());
|
|
934
|
+
clearAgentActivity() {
|
|
935
|
+
this.resetAgentActivity() && this.emit();
|
|
817
936
|
}
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
return this.activeEvents.size === 0 ? null : (t = [
|
|
821
|
-
"EXECUTING_TOOL",
|
|
822
|
-
"SEARCHING",
|
|
823
|
-
"THINKING",
|
|
824
|
-
"TYPING"
|
|
825
|
-
].find((s) => this.activeEvents.has(s))) != null ? t : null;
|
|
937
|
+
resetAgentActivity() {
|
|
938
|
+
return this.activityTimer && (clearTimeout(this.activityTimer), this.activityTimer = null), this.state.agentActivity === null ? !1 : (this.state.agentActivity = null, !0);
|
|
826
939
|
}
|
|
827
940
|
setConnected(e) {
|
|
828
941
|
this.state.isConnected !== e && (this.state.isConnected = e, this.emit());
|
|
@@ -830,15 +943,15 @@ class oe {
|
|
|
830
943
|
addMessage(e) {
|
|
831
944
|
var s, i;
|
|
832
945
|
const t = {
|
|
833
|
-
id: (s = e.id) != null ? s :
|
|
946
|
+
id: (s = e.id) != null ? s : Z("msg"),
|
|
834
947
|
ts: (i = e.ts) != null ? i : Date.now(),
|
|
835
948
|
author: e.author,
|
|
836
949
|
text: e.text
|
|
837
950
|
};
|
|
838
|
-
return this.state.messages.some((
|
|
951
|
+
return this.state.messages.some((n) => n.id === t.id) ? null : (this.state.messages = A([...this.state.messages, t], O), this.resetAgentActivity(), this.persistMessages(), this.touchActivity(), this.emit(), t);
|
|
839
952
|
}
|
|
840
953
|
setMessages(e) {
|
|
841
|
-
this.state.messages =
|
|
954
|
+
this.state.messages = A(e, O), this.persistMessages(), this.emit();
|
|
842
955
|
}
|
|
843
956
|
clearMessages() {
|
|
844
957
|
this.state.messages = [], this.persistMessages(), this.emit();
|
|
@@ -930,7 +1043,7 @@ class oe {
|
|
|
930
1043
|
}
|
|
931
1044
|
isSessionExpired() {
|
|
932
1045
|
const e = this.lastActivityTs;
|
|
933
|
-
return e === 0 ? !1 : Date.now() - e >=
|
|
1046
|
+
return e === 0 ? !1 : Date.now() - e >= H;
|
|
934
1047
|
}
|
|
935
1048
|
getConversationGroups() {
|
|
936
1049
|
const e = this.state.messages;
|
|
@@ -938,7 +1051,7 @@ class oe {
|
|
|
938
1051
|
const t = [];
|
|
939
1052
|
let s = { startTs: e[0].ts, messages: [e[0]] };
|
|
940
1053
|
for (let i = 1; i < e.length; i++)
|
|
941
|
-
e[i].ts - e[i - 1].ts >=
|
|
1054
|
+
e[i].ts - e[i - 1].ts >= H ? (t.push(s), s = { startTs: e[i].ts, messages: [e[i]] }) : s.messages.push(e[i]);
|
|
942
1055
|
return t.push(s), t;
|
|
943
1056
|
}
|
|
944
1057
|
emit() {
|
|
@@ -958,14 +1071,14 @@ class oe {
|
|
|
958
1071
|
const e = localStorage.getItem(this.historyKey);
|
|
959
1072
|
if (!e) return [];
|
|
960
1073
|
const t = JSON.parse(e);
|
|
961
|
-
return Array.isArray(t) ?
|
|
1074
|
+
return Array.isArray(t) ? A(t, O) : [];
|
|
962
1075
|
} catch (e) {
|
|
963
1076
|
return console.error("SpilkiWidget: unable to load messages", e), [];
|
|
964
1077
|
}
|
|
965
1078
|
}
|
|
966
1079
|
}
|
|
967
|
-
function
|
|
968
|
-
const e =
|
|
1080
|
+
function fe(o) {
|
|
1081
|
+
const e = o.replace(/-/g, "+").replace(/_/g, "/"), t = e.padEnd(e.length + (4 - e.length % 4) % 4, "=");
|
|
969
1082
|
if (typeof atob == "function")
|
|
970
1083
|
return decodeURIComponent(
|
|
971
1084
|
Array.prototype.map.call(atob(t), (i) => `%${`00${i.charCodeAt(0).toString(16)}`.slice(-2)}`).join("")
|
|
@@ -975,24 +1088,24 @@ function ne(r) {
|
|
|
975
1088
|
return s.from(t, "base64").toString("utf8");
|
|
976
1089
|
throw new Error("SpilkiWidget: no base64 decoder available");
|
|
977
1090
|
}
|
|
978
|
-
function
|
|
979
|
-
if (!
|
|
980
|
-
const e =
|
|
1091
|
+
function be(o) {
|
|
1092
|
+
if (!o) return null;
|
|
1093
|
+
const e = o.split(".");
|
|
981
1094
|
if (e.length < 2) return null;
|
|
982
1095
|
try {
|
|
983
|
-
const t =
|
|
1096
|
+
const t = fe(e[1]);
|
|
984
1097
|
return JSON.parse(t);
|
|
985
1098
|
} catch (t) {
|
|
986
1099
|
return console.error("SpilkiWidget: unable to parse JWT", t), null;
|
|
987
1100
|
}
|
|
988
1101
|
}
|
|
989
|
-
function
|
|
990
|
-
const e =
|
|
1102
|
+
function ke(o) {
|
|
1103
|
+
const e = be(o);
|
|
991
1104
|
if (!(e != null && e.exp) || typeof e.exp != "number") return !0;
|
|
992
1105
|
const t = Math.floor(Date.now() / 1e3);
|
|
993
1106
|
return e.exp < t + 60;
|
|
994
1107
|
}
|
|
995
|
-
const
|
|
1108
|
+
const ye = {
|
|
996
1109
|
onOpen() {
|
|
997
1110
|
},
|
|
998
1111
|
onClose() {
|
|
@@ -1004,8 +1117,8 @@ const ce = {
|
|
|
1004
1117
|
onTransportChange() {
|
|
1005
1118
|
}
|
|
1006
1119
|
};
|
|
1007
|
-
async function
|
|
1008
|
-
const s = `${
|
|
1120
|
+
async function we(o, e, t) {
|
|
1121
|
+
const s = `${o.replace(/\/$/, "")}/widget/install`, i = await fetch(s, {
|
|
1009
1122
|
method: "POST",
|
|
1010
1123
|
headers: { "Content-Type": "application/json", Origin: window.location.origin },
|
|
1011
1124
|
body: JSON.stringify({ token: e, organisationId: t })
|
|
@@ -1013,202 +1126,206 @@ async function de(r, e, t) {
|
|
|
1013
1126
|
if (!i.ok) throw new Error(`SpilkiWidget: install failed (${i.status})`);
|
|
1014
1127
|
return (await i.json()).accessToken;
|
|
1015
1128
|
}
|
|
1016
|
-
async function
|
|
1017
|
-
const t = `${
|
|
1129
|
+
async function ve(o, e) {
|
|
1130
|
+
const t = `${o.replace(/\/$/, "")}/widget/refresh`, s = await fetch(t, {
|
|
1018
1131
|
method: "POST",
|
|
1019
1132
|
headers: { "X-Authorization": `Bearer ${e}`, Origin: window.location.origin }
|
|
1020
1133
|
});
|
|
1021
1134
|
if (!s.ok) throw new Error(`SpilkiWidget: refresh failed (${s.status})`);
|
|
1022
1135
|
return (await s.json()).accessToken;
|
|
1023
1136
|
}
|
|
1024
|
-
function
|
|
1137
|
+
function Ee(o) {
|
|
1025
1138
|
let e = !1, t = null;
|
|
1026
1139
|
const s = [], i = () => {
|
|
1027
|
-
var
|
|
1028
|
-
if (!
|
|
1140
|
+
var r;
|
|
1141
|
+
if (!o) return null;
|
|
1029
1142
|
if (t) return t;
|
|
1030
1143
|
try {
|
|
1031
|
-
const
|
|
1032
|
-
if (!
|
|
1033
|
-
t = new
|
|
1144
|
+
const l = (r = window.AudioContext) != null ? r : window.webkitAudioContext;
|
|
1145
|
+
if (!l) return null;
|
|
1146
|
+
t = new l();
|
|
1034
1147
|
} catch {
|
|
1035
1148
|
return null;
|
|
1036
1149
|
}
|
|
1037
1150
|
return t;
|
|
1038
|
-
},
|
|
1151
|
+
}, n = () => {
|
|
1039
1152
|
e = !0;
|
|
1040
1153
|
try {
|
|
1041
|
-
const
|
|
1042
|
-
(
|
|
1154
|
+
const r = i();
|
|
1155
|
+
(r == null ? void 0 : r.state) === "suspended" && r.resume().catch(() => {
|
|
1043
1156
|
});
|
|
1044
1157
|
} catch {
|
|
1045
1158
|
}
|
|
1046
|
-
},
|
|
1047
|
-
const
|
|
1048
|
-
|
|
1159
|
+
}, a = (r) => {
|
|
1160
|
+
const l = () => {
|
|
1161
|
+
n(), window.removeEventListener(r, l, !0);
|
|
1049
1162
|
};
|
|
1050
|
-
s.push({ type:
|
|
1163
|
+
s.push({ type: r, listener: l }), window.addEventListener(r, l, { capture: !0, passive: !0 });
|
|
1051
1164
|
};
|
|
1052
|
-
return
|
|
1053
|
-
markUserInteraction:
|
|
1165
|
+
return a("pointerdown"), a("keydown"), {
|
|
1166
|
+
markUserInteraction: n,
|
|
1054
1167
|
play() {
|
|
1055
|
-
if (!
|
|
1056
|
-
const
|
|
1057
|
-
if (!
|
|
1058
|
-
const
|
|
1059
|
-
|
|
1060
|
-
const
|
|
1061
|
-
const f =
|
|
1062
|
-
f.type = "sine", f.frequency.setValueAtTime(
|
|
1063
|
-
}, u =
|
|
1064
|
-
|
|
1168
|
+
if (!o || !e) return;
|
|
1169
|
+
const r = i();
|
|
1170
|
+
if (!r || r.state !== "running") return;
|
|
1171
|
+
const l = r.createGain();
|
|
1172
|
+
l.gain.value = 0.15, l.connect(r.destination);
|
|
1173
|
+
const p = (h, d, y) => {
|
|
1174
|
+
const f = r.createOscillator(), g = r.createGain();
|
|
1175
|
+
f.type = "sine", f.frequency.setValueAtTime(h, d), g.gain.setValueAtTime(1e-4, d), g.gain.exponentialRampToValueAtTime(1, d + 0.012), g.gain.exponentialRampToValueAtTime(1e-4, d + y), f.connect(g), g.connect(l), f.start(d), f.stop(d + y + 0.02);
|
|
1176
|
+
}, u = r.currentTime;
|
|
1177
|
+
p(880, u, 0.08), p(1175, u + 0.09, 0.08);
|
|
1065
1178
|
},
|
|
1066
1179
|
destroy() {
|
|
1067
|
-
s.forEach(({ type:
|
|
1068
|
-
window.removeEventListener(
|
|
1180
|
+
s.forEach(({ type: r, listener: l }) => {
|
|
1181
|
+
window.removeEventListener(r, l, !0);
|
|
1069
1182
|
}), s.length = 0, t && t.close().catch(() => {
|
|
1070
1183
|
}), t = null;
|
|
1071
1184
|
}
|
|
1072
1185
|
};
|
|
1073
1186
|
}
|
|
1074
|
-
function
|
|
1075
|
-
var
|
|
1076
|
-
if (!
|
|
1187
|
+
function z(o) {
|
|
1188
|
+
var B, L, D, j, U;
|
|
1189
|
+
if (!o.org)
|
|
1077
1190
|
throw new Error("SpilkiWidget: org is required");
|
|
1078
|
-
const e =
|
|
1079
|
-
|
|
1080
|
-
const t = { ...
|
|
1081
|
-
let
|
|
1082
|
-
const
|
|
1191
|
+
const e = X(o);
|
|
1192
|
+
ee(e.allowedOriginsHint);
|
|
1193
|
+
const t = { ...ye, ...(B = e.hooks) != null ? B : {} }, s = new me(e.org, { persist: e.persist }), i = Ee(e.sound);
|
|
1194
|
+
let n = (L = s.accessToken) != null ? L : void 0, a = null;
|
|
1195
|
+
const r = () => {
|
|
1083
1196
|
u.setBadge(s.countUnread());
|
|
1084
|
-
},
|
|
1197
|
+
}, l = () => {
|
|
1085
1198
|
s.markRead(), u.setBadge(0);
|
|
1086
|
-
},
|
|
1199
|
+
}, p = async () => a || (a = (async () => {
|
|
1087
1200
|
try {
|
|
1088
|
-
if (
|
|
1201
|
+
if (n && ke(n))
|
|
1089
1202
|
try {
|
|
1090
|
-
|
|
1203
|
+
n = await ve(e.apiBase, n), s.persistAccessToken(n), d.setAccessToken(n);
|
|
1091
1204
|
return;
|
|
1092
1205
|
} catch {
|
|
1093
|
-
|
|
1206
|
+
n = void 0, s.clearAccessToken();
|
|
1094
1207
|
}
|
|
1095
|
-
if (!
|
|
1096
|
-
if (!
|
|
1097
|
-
if (!
|
|
1098
|
-
|
|
1208
|
+
if (!n) {
|
|
1209
|
+
if (!o.installationToken) throw new Error("SpilkiWidget: missing installationToken");
|
|
1210
|
+
if (!o.org) throw new Error("SpilkiWidget: missing org");
|
|
1211
|
+
n = await we(e.apiBase, o.installationToken, o.org), s.persistAccessToken(n), d.setAccessToken(n);
|
|
1099
1212
|
}
|
|
1100
1213
|
} finally {
|
|
1101
|
-
|
|
1214
|
+
a = null;
|
|
1102
1215
|
}
|
|
1103
|
-
})(),
|
|
1216
|
+
})(), a), u = V({
|
|
1104
1217
|
color: e.color,
|
|
1105
|
-
position: (
|
|
1218
|
+
position: (D = e.position) != null ? D : "bottom-right",
|
|
1106
1219
|
onClick: () => {
|
|
1107
|
-
s.snapshot.isOpen ? (s.close(), t.onClose()) : (i.markUserInteraction(), s.open(),
|
|
1220
|
+
s.snapshot.isOpen ? (s.close(), t.onClose()) : (i.markUserInteraction(), s.open(), l(), t.onOpen());
|
|
1108
1221
|
}
|
|
1109
|
-
}),
|
|
1222
|
+
}), h = new ae({
|
|
1110
1223
|
color: e.color,
|
|
1111
|
-
theme:
|
|
1224
|
+
theme: R(e.theme),
|
|
1112
1225
|
position: (j = e.position) != null ? j : "bottom-right",
|
|
1113
1226
|
i18n: e.i18n,
|
|
1114
1227
|
onClose: () => {
|
|
1115
1228
|
s.close(), t.onClose();
|
|
1116
1229
|
},
|
|
1117
1230
|
onSend: (c) => {
|
|
1118
|
-
const
|
|
1119
|
-
|
|
1120
|
-
t.onError(
|
|
1231
|
+
const b = s.addMessage({ author: "user", text: c });
|
|
1232
|
+
b && (h.appendMessage(b), p().then(() => d.send(c, b.id)).catch((m) => {
|
|
1233
|
+
t.onError(m), s.setConnected(!1), h.setOffline(!0);
|
|
1121
1234
|
}));
|
|
1122
1235
|
}
|
|
1123
|
-
}),
|
|
1236
|
+
}), d = new de(
|
|
1124
1237
|
{
|
|
1125
1238
|
apiBase: e.apiBase,
|
|
1126
|
-
accessToken:
|
|
1239
|
+
accessToken: n,
|
|
1127
1240
|
org: e.org,
|
|
1128
1241
|
sessionId: s.sessionId
|
|
1129
1242
|
},
|
|
1130
1243
|
{
|
|
1131
1244
|
onOpen(c) {
|
|
1132
|
-
|
|
1245
|
+
I.transport = c, t.onTransportChange(c), s.setConnected(!0), h.setOffline(!1);
|
|
1133
1246
|
},
|
|
1134
1247
|
onMessage(c) {
|
|
1135
|
-
const
|
|
1136
|
-
|
|
1248
|
+
const m = c.suggestedReplies, k = s.addMessage(c);
|
|
1249
|
+
k && (h.appendMessage(k), k.author === "bot" && m && m.length > 0 && h.setSuggestedReplies(m), !s.snapshot.isOpen && k.author === "bot" && (r(), i.play()), t.onMessage(k));
|
|
1137
1250
|
},
|
|
1138
|
-
onTyping(
|
|
1139
|
-
s.
|
|
1251
|
+
onTyping() {
|
|
1252
|
+
s.handleAgentEvent("TYPING");
|
|
1140
1253
|
},
|
|
1141
1254
|
onAgentEvent(c) {
|
|
1142
|
-
s.handleAgentEvent(c.eventType
|
|
1255
|
+
s.handleAgentEvent(c.eventType);
|
|
1143
1256
|
},
|
|
1144
1257
|
onError(c) {
|
|
1145
|
-
t.onError(c), s.setConnected(!1), s.snapshot.isOpen &&
|
|
1258
|
+
t.onError(c), s.setConnected(!1), s.snapshot.isOpen && h.setOffline(!0);
|
|
1146
1259
|
}
|
|
1147
1260
|
}
|
|
1148
1261
|
);
|
|
1149
|
-
u.mount(),
|
|
1150
|
-
const
|
|
1151
|
-
|
|
1262
|
+
u.mount(), h.mount();
|
|
1263
|
+
const y = (U = e.position) != null ? U : "bottom-right", f = /* @__PURE__ */ new Set([u.element, h.element]), g = new he({
|
|
1264
|
+
bubble: u,
|
|
1265
|
+
widgetHosts: f,
|
|
1266
|
+
position: y
|
|
1267
|
+
}), T = s.snapshot.messages, P = s.isSessionExpired(), x = s.getConversationGroups();
|
|
1268
|
+
if (T.length === 0 && e.welcome) {
|
|
1152
1269
|
const c = {
|
|
1153
1270
|
id: "welcome",
|
|
1154
1271
|
author: "bot",
|
|
1155
1272
|
text: e.welcome,
|
|
1156
1273
|
ts: Date.now()
|
|
1157
1274
|
};
|
|
1158
|
-
s.addMessage(c),
|
|
1159
|
-
} else
|
|
1160
|
-
let
|
|
1161
|
-
const
|
|
1275
|
+
s.addMessage(c), h.appendMessage(c);
|
|
1276
|
+
} else P && T.length > 0 ? h.renderWithConversations(x, []) : x.length > 1 ? h.renderWithConversations(x.slice(0, -1), x[x.length - 1].messages) : h.updateMessages(T);
|
|
1277
|
+
let C = !1;
|
|
1278
|
+
const q = s.subscribe(() => {
|
|
1162
1279
|
const c = s.snapshot;
|
|
1163
|
-
if (u.setOpen(c.isOpen),
|
|
1164
|
-
if (!
|
|
1165
|
-
const
|
|
1166
|
-
|
|
1280
|
+
if (u.setOpen(c.isOpen), h.setAgentActivity(c.agentActivity, e.i18n), h.setOffline(!c.isConnected), h.updateTheme(R(e.theme)), c.isOpen) {
|
|
1281
|
+
if (!C) {
|
|
1282
|
+
const b = s.countUnread() > 0, m = s.lastReadTs;
|
|
1283
|
+
l(), b && h.scrollToFirstUnread(m);
|
|
1167
1284
|
}
|
|
1168
|
-
|
|
1285
|
+
C = !0, h.show();
|
|
1169
1286
|
} else
|
|
1170
|
-
|
|
1171
|
-
}),
|
|
1172
|
-
|
|
1173
|
-
() =>
|
|
1174
|
-
var
|
|
1175
|
-
e.persist && s.persistSession(c.sessionId), s.setConnected(!0), t.onTransportChange((
|
|
1176
|
-
const
|
|
1177
|
-
|
|
1287
|
+
C = !1, h.hide();
|
|
1288
|
+
}), Y = T.length === 0 || P;
|
|
1289
|
+
r(), p().then(
|
|
1290
|
+
() => d.connect().then((c) => {
|
|
1291
|
+
var m, k;
|
|
1292
|
+
e.persist && s.persistSession(c.sessionId), s.setConnected(!0), t.onTransportChange((m = d.kind) != null ? m : "ws");
|
|
1293
|
+
const b = (k = c.suggestedReplies) != null ? k : [];
|
|
1294
|
+
b.length > 0 && Y && h.setSuggestedReplies(b);
|
|
1178
1295
|
})
|
|
1179
1296
|
).catch((c) => {
|
|
1180
|
-
t.onError(c), s.setConnected(!1),
|
|
1297
|
+
t.onError(c), s.setConnected(!1), h.setOffline(!0);
|
|
1181
1298
|
});
|
|
1182
|
-
const
|
|
1299
|
+
const I = {
|
|
1183
1300
|
transport: null,
|
|
1184
1301
|
open() {
|
|
1185
|
-
i.markUserInteraction(), s.open(),
|
|
1302
|
+
i.markUserInteraction(), s.open(), l(), t.onOpen();
|
|
1186
1303
|
},
|
|
1187
1304
|
close() {
|
|
1188
1305
|
s.close(), t.onClose();
|
|
1189
1306
|
},
|
|
1190
1307
|
identify(c) {
|
|
1191
|
-
|
|
1308
|
+
d.setUser(c);
|
|
1192
1309
|
},
|
|
1193
1310
|
destroy() {
|
|
1194
|
-
|
|
1311
|
+
q(), g.destroy(), d.stop(), i.destroy(), u.destroy(), h.destroy(), E === I && (E = null);
|
|
1195
1312
|
}
|
|
1196
1313
|
};
|
|
1197
|
-
return
|
|
1314
|
+
return I;
|
|
1198
1315
|
}
|
|
1199
|
-
function
|
|
1316
|
+
function _() {
|
|
1200
1317
|
var s, i;
|
|
1201
1318
|
if (typeof document == "undefined") return;
|
|
1202
|
-
const
|
|
1203
|
-
if (!
|
|
1204
|
-
const e =
|
|
1319
|
+
const o = document.currentScript;
|
|
1320
|
+
if (!o) return;
|
|
1321
|
+
const e = o.dataset;
|
|
1205
1322
|
if (e.autoinit === "false") return;
|
|
1206
1323
|
const t = e.org;
|
|
1207
1324
|
if (!t) {
|
|
1208
1325
|
console.error("SpilkiWidget: data-org and is required for auto init");
|
|
1209
1326
|
return;
|
|
1210
1327
|
}
|
|
1211
|
-
E =
|
|
1328
|
+
E = z({
|
|
1212
1329
|
org: t,
|
|
1213
1330
|
installationToken: e.installationToken,
|
|
1214
1331
|
apiBase: e.apiBase,
|
|
@@ -1217,9 +1334,9 @@ function N() {
|
|
|
1217
1334
|
});
|
|
1218
1335
|
}
|
|
1219
1336
|
let E = null;
|
|
1220
|
-
typeof window != "undefined" && (window.SpilkiWidget = window.SpilkiWidget || {}, window.SpilkiWidget.init = (
|
|
1221
|
-
E ? E.identify(
|
|
1337
|
+
typeof window != "undefined" && (window.SpilkiWidget = window.SpilkiWidget || {}, window.SpilkiWidget.init = (o) => (E = z(o), E), window.SpilkiWidget.identify = (o) => {
|
|
1338
|
+
E ? E.identify(o) : console.warn("SpilkiWidget: call init() before identify()");
|
|
1222
1339
|
});
|
|
1223
|
-
|
|
1224
|
-
|
|
1340
|
+
_();
|
|
1341
|
+
_();
|
|
1225
1342
|
//# sourceMappingURL=bootstrap.es.js.map
|