@paramms/chat-widget 1.0.37 → 1.0.38
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/chatlist.js +115 -92
- package/dist/chatlist.js.map +1 -1
- package/dist/embed.js +32 -14
- package/dist/embed.js.map +1 -1
- package/dist/index.js +446 -392
- package/dist/index.js.map +1 -1
- package/dist/react.d.ts +2 -1
- package/dist/react.js +330 -309
- package/dist/react.js.map +1 -1
- package/dist/renderer.d.ts +9 -7
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
import { p as
|
|
5
|
-
import { h as
|
|
6
|
-
import { P as
|
|
7
|
-
import { e as
|
|
8
|
-
import { E2ESession as
|
|
9
|
-
const
|
|
10
|
-
class
|
|
1
|
+
var be = Object.defineProperty;
|
|
2
|
+
var xe = (o, e, i) => e in o ? be(o, e, { enumerable: !0, configurable: !0, writable: !0, value: i }) : o[e] = i;
|
|
3
|
+
var v = (o, e, i) => xe(o, typeof e != "symbol" ? e + "" : e, i);
|
|
4
|
+
import { p as ge, r as me, a as ve } from "./codec.js";
|
|
5
|
+
import { h as We } from "./codec.js";
|
|
6
|
+
import { P as ye, C as ke, b as Ce } from "./outbox.js";
|
|
7
|
+
import { e as Ke } from "./outbox.js";
|
|
8
|
+
import { E2ESession as Te, extractX3DHInit as Ie } from "./e2e.js";
|
|
9
|
+
const ae = "http://www.w3.org/2000/svg", Se = 8e3;
|
|
10
|
+
class ze {
|
|
11
11
|
constructor() {
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
v(this, "svg", null);
|
|
13
|
+
v(this, "timers", /* @__PURE__ */ new Set());
|
|
14
14
|
}
|
|
15
15
|
/** Feed every server frame; the overlay reacts to annotation frames only. */
|
|
16
16
|
apply(e) {
|
|
@@ -23,7 +23,7 @@ class ke {
|
|
|
23
23
|
ensureSvg() {
|
|
24
24
|
var i;
|
|
25
25
|
if ((i = this.svg) != null && i.isConnected) return this.svg;
|
|
26
|
-
const e = document.createElementNS(
|
|
26
|
+
const e = document.createElementNS(ae, "svg");
|
|
27
27
|
return e.setAttribute("data-relay-annotations", ""), e.setAttribute("aria-hidden", "true"), e.setAttribute(
|
|
28
28
|
"style",
|
|
29
29
|
"position:fixed;inset:0;width:100vw;height:100vh;pointer-events:none;z-index:2147483000;"
|
|
@@ -32,15 +32,15 @@ class ke {
|
|
|
32
32
|
draw(e) {
|
|
33
33
|
var b;
|
|
34
34
|
if (typeof document > "u" || !((b = e.points) != null && b.length)) return;
|
|
35
|
-
const i = this.ensureSvg(), s = window.innerWidth, a = window.innerHeight,
|
|
36
|
-
|
|
35
|
+
const i = this.ensureSvg(), s = window.innerWidth, a = window.innerHeight, r = document.createElementNS(ae, "polyline");
|
|
36
|
+
r.setAttribute("points", e.points.map((d) => `${(d.x * s).toFixed(1)},${(d.y * a).toFixed(1)}`).join(" ")), r.setAttribute("fill", "none"), r.setAttribute("stroke", e.color || "#ff3b30"), r.setAttribute("stroke-width", String(e.width || 3)), r.setAttribute("stroke-linecap", "round"), r.setAttribute("stroke-linejoin", "round"), r.setAttribute("data-stroke-id", e.id), i.append(r);
|
|
37
37
|
const f = setTimeout(() => {
|
|
38
|
-
|
|
38
|
+
r.style.transition = "opacity 600ms", r.style.opacity = "0";
|
|
39
39
|
const d = setTimeout(() => {
|
|
40
|
-
|
|
40
|
+
r.remove(), this.timers.delete(d);
|
|
41
41
|
}, 650);
|
|
42
42
|
this.timers.add(d), this.timers.delete(f);
|
|
43
|
-
},
|
|
43
|
+
}, Se);
|
|
44
44
|
this.timers.add(f);
|
|
45
45
|
}
|
|
46
46
|
clear() {
|
|
@@ -53,19 +53,29 @@ class ke {
|
|
|
53
53
|
this.timers.clear(), (e = this.svg) == null || e.remove(), this.svg = null;
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
|
-
const
|
|
56
|
+
const re = "objectchat-widget-styles", Ee = ["👍", "❤️", "😂", "😮", "😢", "🙏"], Pe = 400, Le = '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M22 2 11 13M22 2l-7 20-4-9-9-4 20-7z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>', je = `
|
|
57
57
|
.ocw { --ocw-accent:#4F63F5; --ocw-bg:#f3efe9; --ocw-card:#fff; --ocw-line:#ececec; --ocw-ink:#1c1b1a; --ocw-mut:#9b9690;
|
|
58
58
|
position:relative;
|
|
59
59
|
display:flex; flex-direction:column; height:100%; min-height:320px; background:var(--ocw-bg);
|
|
60
60
|
font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif; color:var(--ocw-ink); overflow:hidden; }
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
61
|
+
/* ── Responsive sizing ──────────────────────────────────────────────────────
|
|
62
|
+
* Sizing is driven by the WIDGET'S OWN width (ResizeObserver toggles
|
|
63
|
+
* .ocw-compact below 400px), not the viewport — so a widget embedded in a
|
|
64
|
+
* narrow desktop sidebar sizes the same as one on a phone, and a tablet in
|
|
65
|
+
* landscape keeps comfortable desktop sizing. A viewport query alone can't
|
|
66
|
+
* see the container. Fullscreen (launcher on mobile) additionally gets
|
|
67
|
+
* .ocw-fs from the launcher, which is the only case that should remove the
|
|
68
|
+
* corner radius — an INLINE embed on a phone must NOT take over the page
|
|
69
|
+
* (the old blanket min-height:100dvh rule did exactly that). */
|
|
70
|
+
.ocw.ocw-fs { border-radius:0 !important; }
|
|
71
|
+
.ocw-compact .ocw-bubble { font-size:15px; }
|
|
72
|
+
.ocw-compact.ocw .ocw-input textarea { font-size:16px; } /* ≥16px prevents iOS zoom on focus */
|
|
73
|
+
.ocw-compact .ocw-chip { padding:9px 14px; font-size:14px; }
|
|
74
|
+
.ocw-compact .ocw-modal-card { width:90%; }
|
|
75
|
+
.ocw-compact .ocw-row { max-width:94%; }
|
|
76
|
+
.ocw-compact .ocw-sendbtn { min-width:44px; height:44px; }
|
|
77
|
+
.ocw-compact .ocw-back { width:34px; height:34px; }
|
|
78
|
+
.ocw-compact .ocw-quick button { padding:9px 15px; font-size:14px; }
|
|
69
79
|
/* RTL support: when the host element has dir=rtl, flip layout direction */
|
|
70
80
|
[dir="rtl"] .ocw-row.mine { flex-direction:row; }
|
|
71
81
|
[dir="rtl"] .ocw-row.theirs { flex-direction:row-reverse; }
|
|
@@ -114,7 +124,6 @@ const oe = "objectchat-widget-styles", Ce = ["👍", "❤️", "😂", "😮", "
|
|
|
114
124
|
.ocw-react-pill { display:inline-flex; align-items:center; gap:3px; border:1px solid #e3ded7; border-radius:999px; padding:2px 7px; background:#fff; font-size:12px; cursor:pointer; }
|
|
115
125
|
.ocw-react-pill:hover { border-color:var(--ocw-accent); }
|
|
116
126
|
.ocw-react-pill.mine { border-color:var(--ocw-accent); background:#fff8f5; }
|
|
117
|
-
.ocw-react-add { display:none; position:absolute; bottom:100%; left:0; margin-bottom:4px; background:#fff; border:1px solid #e3ded7; border-radius:14px; padding:6px 8px; box-shadow:0 4px 16px rgba(0,0,0,.12); display:flex; gap:4px; z-index:10; }
|
|
118
127
|
.ocw-react-wrap { position:relative; }
|
|
119
128
|
.ocw-react-wrap:not(:hover) .ocw-react-picker { display:none; }
|
|
120
129
|
.ocw-react-picker { position:absolute; bottom:calc(100% + 4px); left:0; background:#fff; border:1px solid #e3ded7; border-radius:14px; padding:6px 8px; box-shadow:0 4px 16px rgba(0,0,0,.12); display:flex; gap:4px; z-index:10; white-space:nowrap; }
|
|
@@ -203,10 +212,19 @@ const oe = "objectchat-widget-styles", Ce = ["👍", "❤️", "😂", "😮", "
|
|
|
203
212
|
.ocw-footer a:hover { color:var(--ocw-accent); }
|
|
204
213
|
.ocw-attach { background:none;border:none;cursor:pointer;font-size:18px;padding:4px 6px;opacity:.6;flex-none; }
|
|
205
214
|
.ocw-attach:hover { opacity:1; }
|
|
206
|
-
.ocw-input textarea { flex:1; resize:none; border:1px solid #e3ded7; border-radius:22px; padding:11px 16px; font:inherit; font-size:14px; background:#fff; outline:none; max-height:
|
|
215
|
+
.ocw-input textarea { flex:1; min-width:0; resize:none; border:1px solid #e3ded7; border-radius:22px; padding:11px 16px; font:inherit; font-size:14px; line-height:1.4; background:#fff; outline:none; max-height:120px; overflow-y:auto; }
|
|
207
216
|
.ocw-input textarea:focus { border-color:var(--ocw-accent); }
|
|
208
|
-
|
|
217
|
+
/* Send button auto-sizes to its label: the default is a fixed circle around an
|
|
218
|
+
* inline SVG; a TEXT label (i18n.send: "Send", "보내기", "Enviar"…) switches to
|
|
219
|
+
* .ocw-sendbtn-label — a pill whose width follows the text. A fixed 42px
|
|
220
|
+
* circle with 18px type overflowed the moment anyone localized the label. */
|
|
221
|
+
.ocw-sendbtn { min-width:42px; height:42px; border-radius:999px; border:none; background:var(--ocw-accent); color:#fff; font:inherit; font-size:14px; font-weight:600; cursor:pointer; flex:none; display:flex; align-items:center; justify-content:center; padding:0; transition:opacity .15s, transform .1s; }
|
|
222
|
+
.ocw-sendbtn-label { padding:0 16px; white-space:nowrap; }
|
|
223
|
+
.ocw-sendbtn svg { width:19px; height:19px; display:block; }
|
|
224
|
+
.ocw-sendbtn:not(:disabled):hover { transform:scale(1.05); }
|
|
225
|
+
.ocw-sendbtn:not(:disabled):active { transform:scale(.96); }
|
|
209
226
|
.ocw-sendbtn:disabled { opacity:.5; cursor:default; }
|
|
227
|
+
.ocw-sendbtn:focus-visible, .ocw-back:focus-visible, .ocw-chip:focus-visible { outline:2px solid var(--ocw-accent); outline-offset:2px; }
|
|
210
228
|
.ocw-cobrowse-btn { display:none; }
|
|
211
229
|
.ocw-cobrowse-btn.show { display:inline-flex; }
|
|
212
230
|
.ocw-cobrowse-btn.on { color:var(--ocw-accent); border-color:var(--ocw-accent); }
|
|
@@ -226,23 +244,23 @@ const oe = "objectchat-widget-styles", Ce = ["👍", "❤️", "😂", "😮", "
|
|
|
226
244
|
.ocw-bubble-wrap:hover .ocw-translate-btn { opacity:1; }
|
|
227
245
|
.ocw-translated-tag { font-size:10px; color:var(--ocw-mut); margin-top:2px; }
|
|
228
246
|
`;
|
|
229
|
-
function
|
|
230
|
-
if (typeof document > "u" || document.getElementById(
|
|
247
|
+
function Ae() {
|
|
248
|
+
if (typeof document > "u" || document.getElementById(re)) return;
|
|
231
249
|
const o = document.createElement("style");
|
|
232
|
-
o.id =
|
|
250
|
+
o.id = re, o.textContent = je, document.head.appendChild(o);
|
|
233
251
|
}
|
|
234
252
|
function t(o, e, i) {
|
|
235
253
|
const s = document.createElement(o);
|
|
236
254
|
return e && (s.className = e), i !== void 0 && (s.textContent = i), s;
|
|
237
255
|
}
|
|
238
|
-
function
|
|
256
|
+
function $e(o) {
|
|
239
257
|
try {
|
|
240
258
|
return new Date(o).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
|
241
259
|
} catch {
|
|
242
260
|
return "";
|
|
243
261
|
}
|
|
244
262
|
}
|
|
245
|
-
function
|
|
263
|
+
function X(o) {
|
|
246
264
|
var e;
|
|
247
265
|
switch (o.kind) {
|
|
248
266
|
case "text":
|
|
@@ -259,61 +277,66 @@ function W(o) {
|
|
|
259
277
|
return `📅 ${o.title} — ${new Date(o.startIso).toLocaleString()}`;
|
|
260
278
|
}
|
|
261
279
|
}
|
|
262
|
-
class
|
|
280
|
+
class Be {
|
|
263
281
|
/** Last seq the guest has seen per conversationId — used to compute unread badges. */
|
|
264
282
|
constructor(e, i, s, a = {}) {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
283
|
+
v(this, "scroll");
|
|
284
|
+
v(this, "chips");
|
|
285
|
+
v(this, "typing");
|
|
286
|
+
v(this, "quick");
|
|
287
|
+
v(this, "formHost");
|
|
288
|
+
v(this, "csatPanel");
|
|
289
|
+
v(this, "offlinePanel");
|
|
290
|
+
v(this, "preChatPanel");
|
|
291
|
+
v(this, "deflectPanel");
|
|
292
|
+
v(this, "preChatBuilt", !1);
|
|
293
|
+
v(this, "preChatDone", !1);
|
|
294
|
+
v(this, "footer");
|
|
295
|
+
v(this, "input");
|
|
296
|
+
v(this, "subjectCard");
|
|
297
|
+
v(this, "e2eBadge");
|
|
298
|
+
v(this, "statusBadge");
|
|
299
|
+
v(this, "headerName");
|
|
300
|
+
v(this, "connStatus");
|
|
301
|
+
v(this, "typingTimer", null);
|
|
302
|
+
v(this, "csatSubmitted", !1);
|
|
303
|
+
v(this, "sendBtn");
|
|
304
|
+
/** Container-driven responsive sizing — toggles .ocw-compact (see CSS note). */
|
|
305
|
+
v(this, "compactObserver", null);
|
|
285
306
|
// ── Co-browsing (shared whiteboard) ─────────────────────────────────────
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
307
|
+
v(this, "cobrowseBtn");
|
|
308
|
+
v(this, "cobrowseCanvas");
|
|
309
|
+
v(this, "cobrowseToolbar");
|
|
310
|
+
v(this, "cobrowseHint");
|
|
311
|
+
v(this, "cobrowseActive", !1);
|
|
312
|
+
v(this, "cobrowseColor", "#f5713c");
|
|
313
|
+
v(this, "lastAnnotationVersion", -1);
|
|
314
|
+
v(this, "storeRef", null);
|
|
315
|
+
v(this, "scrollCleanup", null);
|
|
295
316
|
// ── Live translation ──────────────────────────────────────────────────-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
this
|
|
301
|
-
|
|
317
|
+
v(this, "translationCache", /* @__PURE__ */ new Map());
|
|
318
|
+
v(this, "showingTranslation", /* @__PURE__ */ new Set());
|
|
319
|
+
/** Whether the subject card (server Subject entity, mount config fallback)
|
|
320
|
+
* has been built — built once when data first arrives. */
|
|
321
|
+
v(this, "subjectBuilt", !1);
|
|
322
|
+
var k, E, I, A, $, z, q, C, j, D;
|
|
323
|
+
this.root = e, this.me = i, this.h = s, this.cfg = a, Ae(), e.replaceChildren(), e.classList.add("ocw"), a.accent && e.style.setProperty("--ocw-accent", a.accent);
|
|
324
|
+
const r = t("div", "ocw-head");
|
|
302
325
|
if (this.h.onBack) {
|
|
303
326
|
const x = t("button", "ocw-back", "‹");
|
|
304
|
-
x.type = "button", x.setAttribute("aria-label", "Back"), x.addEventListener("click", () => this.h.onBack()),
|
|
327
|
+
x.type = "button", x.setAttribute("aria-label", "Back"), x.addEventListener("click", () => this.h.onBack()), r.append(x);
|
|
305
328
|
}
|
|
306
329
|
const f = t("div", "ocw-avatar");
|
|
307
|
-
if ((
|
|
330
|
+
if ((k = a.userInfo) != null && k.avatar) {
|
|
308
331
|
const x = document.createElement("img");
|
|
309
332
|
x.src = a.userInfo.avatar, x.alt = a.userInfo.name ?? "You", x.style.cssText = "width:100%;height:100%;border-radius:50%;object-fit:cover", f.append(x);
|
|
310
333
|
} else
|
|
311
|
-
f.textContent = (
|
|
312
|
-
|
|
334
|
+
f.textContent = (E = a.userInfo) != null && E.name ? a.userInfo.name[0].toUpperCase() : "🧑";
|
|
335
|
+
r.append(f);
|
|
313
336
|
const b = t("div", "ocw-head-main");
|
|
314
|
-
this.headerName = t("div", "ocw-head-name", ((I = a.subject) == null ? void 0 : I.ownerLabel) ?? ((
|
|
337
|
+
this.headerName = t("div", "ocw-head-name", ((I = a.subject) == null ? void 0 : I.ownerLabel) ?? ((A = a.subject) == null ? void 0 : A.title) ?? ""), b.append(this.headerName), ($ = a.subject) != null && $.subtitle && b.append(t("div", "ocw-head-meta", a.subject.subtitle)), r.append(b), this.statusBadge = t("span", "ocw-badge", ((z = a.subject) == null ? void 0 : z.status) ?? ""), (q = a.subject) != null && q.status || (this.statusBadge.style.display = "none"), r.append(this.statusBadge), this.e2eBadge = t("span", "ocw-e2e", "🔒 E2E"), this.e2eBadge.style.display = "none", r.append(this.e2eBadge), this.connStatus = t("span", "ocw-conn-status"), this.connStatus.style.display = "none", r.append(this.connStatus), this.cobrowseBtn = t("button", "ocw-menu ocw-cobrowse-btn", "🖍"), this.cobrowseBtn.title = "Shared whiteboard — draw to point things out together", this.cobrowseBtn.addEventListener("click", () => {
|
|
315
338
|
this.cobrowseActive = !this.cobrowseActive, this.updateCobrowseUI();
|
|
316
|
-
}),
|
|
339
|
+
}), r.append(this.cobrowseBtn), r.append(t("button", "ocw-menu", "⋯")), this.chips = t("div", "ocw-chiprow"), this.scroll = t("div", "ocw-scroll"), this.subjectCard = t("div", "ocw-subject"), this.typing = t("div", "ocw-typing");
|
|
317
340
|
const d = t("div", "ocw-typing-bubble");
|
|
318
341
|
d.append(t("div", "ocw-typing-dot"), t("div", "ocw-typing-dot"), t("div", "ocw-typing-dot")), this.typing.append(t("div", "ocw-dot", "🧑"), d), this.quick = t("div", "ocw-quick");
|
|
319
342
|
for (const x of a.quickReplies ?? []) {
|
|
@@ -322,38 +345,48 @@ class Ee {
|
|
|
322
345
|
this.h.onSend(x), this.quick.style.display = "none";
|
|
323
346
|
}), this.quick.append(S);
|
|
324
347
|
}
|
|
325
|
-
this.formHost = t("div", "ocw-form-host"), this.csatPanel = t("div", "ocw-csat"), this.csatPanel.style.display = "none", this.offlinePanel = t("div", "ocw-offline"), this.offlinePanel.style.display = "none", this.preChatPanel = t("div", "ocw-prechat"), this.preChatPanel.style.display = "none", this.deflectPanel = t("div", "ocw-deflect"), this.deflectPanel.style.display = "none", this.input = t("textarea", void 0), this.input.rows = 1, this.input.placeholder = "Message…";
|
|
326
|
-
const
|
|
327
|
-
|
|
348
|
+
this.formHost = t("div", "ocw-form-host"), this.csatPanel = t("div", "ocw-csat"), this.csatPanel.style.display = "none", this.offlinePanel = t("div", "ocw-offline"), this.offlinePanel.style.display = "none", this.preChatPanel = t("div", "ocw-prechat"), this.preChatPanel.style.display = "none", this.deflectPanel = t("div", "ocw-deflect"), this.deflectPanel.style.display = "none", this.input = t("textarea", void 0), this.input.rows = 1, this.input.placeholder = ((C = a.i18n) == null ? void 0 : C.placeholder) ?? "Message…";
|
|
349
|
+
const h = t("button", "ocw-sendbtn");
|
|
350
|
+
h.type = "button";
|
|
351
|
+
const y = (j = a.i18n) == null ? void 0 : j.send;
|
|
352
|
+
y ? (h.textContent = y, h.classList.add("ocw-sendbtn-label"), h.setAttribute("aria-label", y)) : (h.innerHTML = Le, h.setAttribute("aria-label", "Send message")), h.disabled = !0, this.sendBtn = h, h.addEventListener("click", () => this.flushSend()), this.input.addEventListener("input", () => {
|
|
328
353
|
var x, S;
|
|
329
|
-
this.storeRef && !this.storeRef.messages().some((
|
|
354
|
+
this.sendBtn.disabled = this.input.value.trim().length === 0, this.autoGrowInput(), this.storeRef && !this.storeRef.messages().some((M) => M.senderRole === "guest") ? (S = (x = this.h).onDeflectQuery) == null || S.call(x, this.input.value) : this.hideDeflection();
|
|
330
355
|
}), this.input.addEventListener("keydown", (x) => {
|
|
331
356
|
x.isComposing || x.keyCode === 229 || (x.key === "Enter" && !x.shiftKey ? (x.preventDefault(), this.flushSend()) : this.signalTyping());
|
|
332
357
|
});
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
const
|
|
336
|
-
|
|
358
|
+
const c = t("button", "ocw-attach", "📎");
|
|
359
|
+
c.title = "Attach image or file";
|
|
360
|
+
const u = document.createElement("input");
|
|
361
|
+
u.type = "file", u.accept = "image/*,.pdf,.txt,.doc,.docx", u.style.display = "none", c.addEventListener("click", () => u.click()), u.addEventListener("change", () => {
|
|
337
362
|
var x;
|
|
338
|
-
(x =
|
|
363
|
+
(x = u.files) != null && x[0] && this.h.onAttach && this.h.onAttach(u.files[0]), u.value = "";
|
|
339
364
|
});
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
const
|
|
343
|
-
((
|
|
365
|
+
const l = t("div", "ocw-input");
|
|
366
|
+
l.append(c, u, this.input, h);
|
|
367
|
+
const T = t("div", "ocw-footer");
|
|
368
|
+
((D = a.i18n) == null ? void 0 : D.poweredBy) !== void 0 ? T.textContent = a.i18n.poweredBy : T.innerHTML = 'Powered by <a href="https://relay.paramms.com" target="_blank" rel="noopener">Relay</a>', this.footer = T, e.append(r, this.chips, this.scroll, this.typing, this.quick, this.formHost, this.csatPanel, this.offlinePanel, this.preChatPanel, this.deflectPanel, l, this.footer), this.cobrowseCanvas = t("canvas", "ocw-cobrowse-canvas"), this.cobrowseToolbar = t("div", "ocw-cobrowse-toolbar");
|
|
344
369
|
for (const x of ["#f5713c", "#1c1b1a", "#2563eb", "#16a34a", "#dc2626"]) {
|
|
345
370
|
const S = t("button", "ocw-cobrowse-swatch");
|
|
346
371
|
S.style.background = x, S.type = "button", x === this.cobrowseColor && S.classList.add("sel"), S.addEventListener("click", () => {
|
|
347
372
|
this.cobrowseColor = x;
|
|
348
|
-
for (const
|
|
373
|
+
for (const M of this.cobrowseToolbar.querySelectorAll(".ocw-cobrowse-swatch")) M.classList.remove("sel");
|
|
349
374
|
S.classList.add("sel");
|
|
350
375
|
}), this.cobrowseToolbar.append(S);
|
|
351
376
|
}
|
|
352
|
-
const
|
|
353
|
-
|
|
377
|
+
const m = t("button", "ocw-cobrowse-clear", "Clear");
|
|
378
|
+
m.addEventListener("click", () => {
|
|
354
379
|
var x, S;
|
|
355
380
|
return (S = (x = this.h).onAnnotateClear) == null ? void 0 : S.call(x);
|
|
356
|
-
}), this.cobrowseToolbar.append(
|
|
381
|
+
}), this.cobrowseToolbar.append(m), this.cobrowseHint = t("div", "ocw-cobrowse-hint", "🖍 Draw to point things out — visible to both sides"), e.append(this.cobrowseCanvas, this.cobrowseToolbar, this.cobrowseHint), this.bindCobrowsePointerEvents();
|
|
382
|
+
const w = (x) => {
|
|
383
|
+
e.classList.toggle("ocw-compact", x > 0 && x < Pe);
|
|
384
|
+
};
|
|
385
|
+
w(e.clientWidth), typeof ResizeObserver < "u" && (this.compactObserver = new ResizeObserver((x) => {
|
|
386
|
+
var M;
|
|
387
|
+
const S = ((M = x[0]) == null ? void 0 : M.contentRect.width) ?? e.clientWidth;
|
|
388
|
+
w(S);
|
|
389
|
+
}), this.compactObserver.observe(e));
|
|
357
390
|
}
|
|
358
391
|
/** Returns the scroll container so history.ts can attach scroll listeners. */
|
|
359
392
|
getScrollEl() {
|
|
@@ -366,50 +399,53 @@ class Ee {
|
|
|
366
399
|
}
|
|
367
400
|
/** Call when the widget is unmounted. Disconnects scroll listeners and clears timers. */
|
|
368
401
|
destroy() {
|
|
369
|
-
var e;
|
|
370
|
-
(e = this.scrollCleanup) == null || e.call(this), this.scrollCleanup = null, this.typingTimer && (clearTimeout(this.typingTimer), this.typingTimer = null);
|
|
402
|
+
var e, i;
|
|
403
|
+
(e = this.scrollCleanup) == null || e.call(this), this.scrollCleanup = null, this.typingTimer && (clearTimeout(this.typingTimer), this.typingTimer = null), (i = this.compactObserver) == null || i.disconnect(), this.compactObserver = null;
|
|
371
404
|
}
|
|
372
|
-
/** Render list rows, optionally filtered by search query. */
|
|
373
|
-
/** Build a single WhatsApp-style conversation row. */
|
|
374
|
-
/** Returns true when the chat screen is visible (not the list). */
|
|
375
|
-
/** Navigate to the chat screen (slide list left, slide chat in from right). */
|
|
376
|
-
/** Navigate back to the list screen. */
|
|
377
405
|
flushSend() {
|
|
378
406
|
this.hideDeflection();
|
|
379
407
|
const e = this.input.value.trim();
|
|
380
|
-
e && (this.input.value = "", this.h.onTyping(!1), this.h.onSend(e));
|
|
408
|
+
e && (this.input.value = "", this.sendBtn.disabled = !0, this.autoGrowInput(), this.h.onTyping(!1), this.h.onSend(e));
|
|
409
|
+
}
|
|
410
|
+
/** Grow the composer with its content (up to the CSS max-height), collapse
|
|
411
|
+
* when cleared. scrollHeight is 0 in non-layout environments (jsdom) —
|
|
412
|
+
* skip there so tests and SSR-ish mounts are unaffected. */
|
|
413
|
+
autoGrowInput() {
|
|
414
|
+
this.input.style.height = "auto";
|
|
415
|
+
const e = this.input.scrollHeight;
|
|
416
|
+
e > 0 ? this.input.style.height = `${Math.min(e, 120)}px` : this.input.style.removeProperty("height");
|
|
381
417
|
}
|
|
382
418
|
signalTyping() {
|
|
383
419
|
const e = this.input.value.trim().slice(0, 100) || void 0;
|
|
384
420
|
this.h.onTyping(!0, e), this.typingTimer && clearTimeout(this.typingTimer), this.typingTimer = setTimeout(() => this.h.onTyping(!1), 2e3);
|
|
385
421
|
}
|
|
386
422
|
render(e) {
|
|
387
|
-
var
|
|
423
|
+
var c, u, l, T, m;
|
|
388
424
|
if (this.storeRef = e, this.cobrowseBtn.classList.toggle("show", !!e.subject), !e.subject && this.cobrowseActive && (this.cobrowseActive = !1, this.updateCobrowseUI()), this.cobrowseActive && e.annotationVersion !== this.lastAnnotationVersion && (this.lastAnnotationVersion = e.annotationVersion, this.resizeCobrowseCanvas(), this.redrawCobrowse()), e.accent && this.root.style.setProperty("--ocw-accent", e.accent), this.e2eBadge.style.display = e.e2e ? "inline-flex" : "none", this.buildSubjectCard(e), e.subject) {
|
|
389
|
-
const
|
|
390
|
-
|
|
425
|
+
const w = (c = this.cfg.subject) == null ? void 0 : c.ownerLabel;
|
|
426
|
+
w && (this.headerName.textContent = w);
|
|
391
427
|
}
|
|
392
428
|
this.quick.style.display = e.messages().length === 0 ? "flex" : "none", this.chips.replaceChildren();
|
|
393
429
|
const i = e.visibleActions();
|
|
394
430
|
this.chips.style.display = i.length ? "flex" : "none";
|
|
395
|
-
for (const
|
|
431
|
+
for (const w of i) this.chips.append(this.chipEl(w));
|
|
396
432
|
const s = this.scroll.scrollHeight, a = this.scroll.scrollTop;
|
|
397
433
|
if (this.scroll.replaceChildren(), this.subjectCard.childNodes.length && this.scroll.append(this.subjectCard), e.hasMoreHistory) {
|
|
398
|
-
const
|
|
399
|
-
|
|
434
|
+
const w = t("div", "ocw-load-more");
|
|
435
|
+
w.textContent = "↑ Loading earlier messages…", w.style.pointerEvents = "none", this.scroll.append(w);
|
|
400
436
|
}
|
|
401
|
-
let
|
|
402
|
-
for (const
|
|
403
|
-
this.scroll.append(this.messageEl(
|
|
404
|
-
a > 20 ? this.scroll.scrollTop = this.scroll.scrollHeight - s + a : this.scroll.scrollTop = this.scroll.scrollHeight,
|
|
437
|
+
let r = 0;
|
|
438
|
+
for (const w of e.messages())
|
|
439
|
+
this.scroll.append(this.messageEl(w, e)), w.senderId !== this.me && w.seq > r && (r = w.seq);
|
|
440
|
+
a > 20 ? this.scroll.scrollTop = this.scroll.scrollHeight - s + a : this.scroll.scrollTop = this.scroll.scrollHeight, r > 0 && this.h.onReadUpTo(r);
|
|
405
441
|
const f = [...e.typing];
|
|
406
442
|
this.typing.classList.toggle("active", f.length > 0);
|
|
407
443
|
const b = this.typing.querySelector(".ocw-typing-bubble");
|
|
408
444
|
b && b.setAttribute("aria-label", f.length ? "typing" : ""), this.footer.style.display = e.whiteLabel ? "none" : "block";
|
|
409
|
-
const d = e.messages().some((
|
|
410
|
-
!!((u = e.preChat) != null && u.enabled) && !this.preChatDone && !d && (e.preChat.showWhen !== "offline" || e.offline) ? (this.preChatBuilt || this.buildPreChatPanel(e.preChat), this.preChatPanel.style.display = "block", this.offlinePanel.style.display = "none", (l = this.root.querySelector(".ocw-input")) == null || l.style.setProperty("display", "none")) : (this.preChatPanel.style.display = "none", e.offline ? (this.offlinePanel.style.display === "none" && this.buildOfflinePanel(e.offlineMessage), this.offlinePanel.style.display = "block", (
|
|
411
|
-
const
|
|
412
|
-
this.h.onCsat && !this.csatSubmitted &&
|
|
445
|
+
const d = e.messages().some((w) => w.senderRole === "guest");
|
|
446
|
+
!!((u = e.preChat) != null && u.enabled) && !this.preChatDone && !d && (e.preChat.showWhen !== "offline" || e.offline) ? (this.preChatBuilt || this.buildPreChatPanel(e.preChat), this.preChatPanel.style.display = "block", this.offlinePanel.style.display = "none", (l = this.root.querySelector(".ocw-input")) == null || l.style.setProperty("display", "none")) : (this.preChatPanel.style.display = "none", e.offline ? (this.offlinePanel.style.display === "none" && this.buildOfflinePanel(e.offlineMessage), this.offlinePanel.style.display = "block", (T = this.root.querySelector(".ocw-input")) == null || T.style.setProperty("display", "none")) : (this.offlinePanel.style.display = "none", (m = this.root.querySelector(".ocw-input")) == null || m.style.removeProperty("display")));
|
|
447
|
+
const y = ["resolved", "closed", "sold", "issued", "checked_out"];
|
|
448
|
+
this.h.onCsat && !this.csatSubmitted && y.includes(e.state) && e.messages().length > 0 && (this.csatPanel.style.display === "none" && this.buildCsatPanel(), this.csatPanel.style.display = "block");
|
|
413
449
|
}
|
|
414
450
|
setConnStatus(e, i) {
|
|
415
451
|
if (e === "open") {
|
|
@@ -427,63 +463,63 @@ class Ee {
|
|
|
427
463
|
s.placeholder = "Your name", s.type = "text";
|
|
428
464
|
const a = t("input", "ocw-offline-input");
|
|
429
465
|
a.placeholder = "Your email", a.type = "email";
|
|
430
|
-
const
|
|
431
|
-
|
|
466
|
+
const r = t("textarea", "ocw-offline-input");
|
|
467
|
+
r.placeholder = "Your message", r.rows = 3;
|
|
432
468
|
const f = t("button", "ocw-offline-submit", "Send message");
|
|
433
|
-
f.addEventListener("click", () => {
|
|
434
|
-
!a.value.trim() || !
|
|
469
|
+
f.type = "button", f.addEventListener("click", () => {
|
|
470
|
+
!a.value.trim() || !r.value.trim() || (f.disabled = !0, this.h.onSend(`[Offline form]
|
|
435
471
|
Name: ${s.value || "Anonymous"}
|
|
436
472
|
Email: ${a.value}
|
|
437
|
-
Message: ${
|
|
438
|
-
}), i.append(s, a,
|
|
473
|
+
Message: ${r.value}`), this.offlinePanel.replaceChildren(t("div", "ocw-offline-thanks", "✓ Message sent! We'll reply to your email.")));
|
|
474
|
+
}), i.append(s, a, r, f), this.offlinePanel.append(i);
|
|
439
475
|
}
|
|
440
476
|
buildPreChatPanel(e) {
|
|
441
477
|
var d;
|
|
442
478
|
this.preChatBuilt = !0, this.preChatPanel.replaceChildren(), this.preChatPanel.append(t("div", "ocw-prechat-title", e.title ?? "Before we start…"));
|
|
443
479
|
const i = t("div", "ocw-offline-form"), s = {};
|
|
444
|
-
for (const
|
|
445
|
-
const
|
|
446
|
-
|
|
480
|
+
for (const h of e.fields ?? ["name", "email"]) {
|
|
481
|
+
const y = t("input", "ocw-offline-input");
|
|
482
|
+
y.type = h === "email" ? "email" : h === "phone" ? "tel" : "text", y.placeholder = h === "name" ? "Your name" : h === "email" ? "Your email" : "Your phone number", s[h] = y, i.append(y);
|
|
447
483
|
}
|
|
448
484
|
let a = null;
|
|
449
485
|
if ((d = e.topics) != null && d.length) {
|
|
450
486
|
a = t("select", void 0);
|
|
451
|
-
const
|
|
452
|
-
|
|
453
|
-
for (const
|
|
454
|
-
const
|
|
455
|
-
|
|
487
|
+
const h = document.createElement("option");
|
|
488
|
+
h.value = "", h.textContent = "What is this about?", a.append(h);
|
|
489
|
+
for (const y of e.topics) {
|
|
490
|
+
const c = document.createElement("option");
|
|
491
|
+
c.value = y, c.textContent = y, a.append(c);
|
|
456
492
|
}
|
|
457
493
|
i.append(a);
|
|
458
494
|
}
|
|
459
|
-
let
|
|
495
|
+
let r = null, f = null;
|
|
460
496
|
if (e.callbackOption) {
|
|
461
|
-
const
|
|
462
|
-
|
|
497
|
+
const h = t("label", "ocw-prechat-cb");
|
|
498
|
+
r = document.createElement("input"), r.type = "checkbox", h.append(r, document.createTextNode("📞 Request a call back")), i.append(h), s.phone || (f = t("input", "ocw-offline-input"), f.type = "tel", f.placeholder = "Phone number for the call", f.style.display = "none", r.addEventListener("change", () => f.style.setProperty("display", r.checked ? "block" : "none")), i.append(f));
|
|
463
499
|
}
|
|
464
500
|
const b = t("button", "ocw-offline-submit", "Start chat");
|
|
465
|
-
b.addEventListener("click", () => {
|
|
466
|
-
var u, l,
|
|
467
|
-
const
|
|
468
|
-
if (s.email && (!
|
|
501
|
+
b.type = "button", b.addEventListener("click", () => {
|
|
502
|
+
var u, l, T, m, w, k, E;
|
|
503
|
+
const h = (u = s.email) == null ? void 0 : u.value.trim();
|
|
504
|
+
if (s.email && (!h || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(h))) {
|
|
469
505
|
s.email.focus();
|
|
470
506
|
return;
|
|
471
507
|
}
|
|
472
|
-
const
|
|
473
|
-
if (
|
|
474
|
-
(
|
|
508
|
+
const y = !!(r != null && r.checked), c = (((l = s.phone) == null ? void 0 : l.value) ?? (f == null ? void 0 : f.value) ?? "").trim();
|
|
509
|
+
if (y && !c) {
|
|
510
|
+
(T = s.phone ?? f) == null || T.focus();
|
|
475
511
|
return;
|
|
476
512
|
}
|
|
477
513
|
if (a && ((m = e.topics) != null && m.length) && !a.value) {
|
|
478
514
|
a.focus();
|
|
479
515
|
return;
|
|
480
516
|
}
|
|
481
|
-
this.completePreChat(), (
|
|
482
|
-
...(
|
|
483
|
-
...
|
|
484
|
-
...
|
|
517
|
+
b.disabled = !0, this.completePreChat(), (E = (k = this.h).onPreChat) == null || E.call(k, {
|
|
518
|
+
...(w = s.name) != null && w.value.trim() ? { name: s.name.value.trim() } : {},
|
|
519
|
+
...h ? { email: h } : {},
|
|
520
|
+
...c ? { phone: c } : {},
|
|
485
521
|
...a != null && a.value ? { topic: a.value } : {},
|
|
486
|
-
...
|
|
522
|
+
...y ? { callback: !0 } : {}
|
|
487
523
|
});
|
|
488
524
|
}), i.append(b), this.preChatPanel.append(i);
|
|
489
525
|
}
|
|
@@ -509,15 +545,13 @@ Message: ${c.value}`), this.offlinePanel.replaceChildren(t("div", "ocw-offline-t
|
|
|
509
545
|
const e = t("div", "ocw-csat-stars"), i = [];
|
|
510
546
|
for (let s = 1; s <= 5; s++) {
|
|
511
547
|
const a = t("button", "ocw-csat-star", "★");
|
|
512
|
-
a.dataset.score = String(s), a.addEventListener("mouseenter", () => i.forEach((
|
|
513
|
-
var
|
|
514
|
-
this.csatSubmitted = !0, this.csatPanel.replaceChildren(t("div", "ocw-csat-done", `Thanks for your ${s}★ rating!`)), (f = (
|
|
548
|
+
a.dataset.score = String(s), a.addEventListener("mouseenter", () => i.forEach((r, f) => r.classList.toggle("lit", f < s))), a.addEventListener("mouseleave", () => i.forEach((r) => r.classList.remove("lit"))), a.addEventListener("click", () => {
|
|
549
|
+
var r, f;
|
|
550
|
+
this.csatSubmitted = !0, this.csatPanel.replaceChildren(t("div", "ocw-csat-done", `Thanks for your ${s}★ rating!`)), (f = (r = this.h).onCsat) == null || f.call(r, s);
|
|
515
551
|
}), i.push(a), e.append(a);
|
|
516
552
|
}
|
|
517
553
|
this.csatPanel.append(e);
|
|
518
554
|
}
|
|
519
|
-
/** Subject card from the server's Subject entity (per chatroom), with the
|
|
520
|
-
* mount config as a fallback. Built once when data first arrives. */
|
|
521
555
|
// ── Co-browsing (shared whiteboard) ──────────────────────────────────────
|
|
522
556
|
updateCobrowseUI() {
|
|
523
557
|
this.cobrowseCanvas.classList.toggle("active", this.cobrowseActive), this.cobrowseToolbar.classList.toggle("active", this.cobrowseActive), this.cobrowseHint.classList.toggle("active", this.cobrowseActive), this.cobrowseBtn.classList.toggle("on", this.cobrowseActive), this.cobrowseActive && (this.resizeCobrowseCanvas(), this.redrawCobrowse());
|
|
@@ -532,7 +566,7 @@ Message: ${c.value}`), this.offlinePanel.replaceChildren(t("div", "ocw-offline-t
|
|
|
532
566
|
if (!i || e.points.length < 2) return;
|
|
533
567
|
const s = this.cobrowseCanvas.width, a = this.cobrowseCanvas.height;
|
|
534
568
|
i.strokeStyle = e.color, i.lineWidth = Math.max(1, e.width * Math.min(s, a)), i.lineJoin = "round", i.lineCap = "round", i.beginPath(), i.moveTo(e.points[0].x * s, e.points[0].y * a);
|
|
535
|
-
for (const
|
|
569
|
+
for (const r of e.points.slice(1)) i.lineTo(r.x * s, r.y * a);
|
|
536
570
|
i.stroke();
|
|
537
571
|
}
|
|
538
572
|
redrawCobrowse() {
|
|
@@ -546,15 +580,15 @@ Message: ${c.value}`), this.offlinePanel.replaceChildren(t("div", "ocw-offline-t
|
|
|
546
580
|
bindCobrowsePointerEvents() {
|
|
547
581
|
let e = !1, i = [];
|
|
548
582
|
const s = (f) => {
|
|
549
|
-
const b = this.cobrowseCanvas.getBoundingClientRect(), d = b.width > 0 ? (f.clientX - b.left) / b.width : 0,
|
|
550
|
-
return { x: Math.min(1, Math.max(0, d)), y: Math.min(1, Math.max(0,
|
|
583
|
+
const b = this.cobrowseCanvas.getBoundingClientRect(), d = b.width > 0 ? (f.clientX - b.left) / b.width : 0, h = b.height > 0 ? (f.clientY - b.top) / b.height : 0;
|
|
584
|
+
return { x: Math.min(1, Math.max(0, d)), y: Math.min(1, Math.max(0, h)) };
|
|
551
585
|
}, a = 6e-3;
|
|
552
586
|
this.cobrowseCanvas.addEventListener("pointerdown", (f) => {
|
|
553
587
|
this.cobrowseActive && (e = !0, i = [s(f)], this.cobrowseCanvas.setPointerCapture(f.pointerId));
|
|
554
588
|
}), this.cobrowseCanvas.addEventListener("pointermove", (f) => {
|
|
555
589
|
e && (i.push(s(f)), this.redrawCobrowse(), this.drawStroke({ points: i, color: this.cobrowseColor, width: a }));
|
|
556
590
|
});
|
|
557
|
-
const
|
|
591
|
+
const r = (f) => {
|
|
558
592
|
var b, d;
|
|
559
593
|
if (e) {
|
|
560
594
|
e = !1, i.length > 1 && ((d = (b = this.h).onAnnotate) == null || d.call(b, { id: `an_${Date.now()}_${Math.random().toString(36).slice(2)}`, points: i, color: this.cobrowseColor, width: a })), i = [];
|
|
@@ -564,17 +598,17 @@ Message: ${c.value}`), this.offlinePanel.replaceChildren(t("div", "ocw-offline-t
|
|
|
564
598
|
}
|
|
565
599
|
}
|
|
566
600
|
};
|
|
567
|
-
this.cobrowseCanvas.addEventListener("pointerup",
|
|
601
|
+
this.cobrowseCanvas.addEventListener("pointerup", r), this.cobrowseCanvas.addEventListener("pointercancel", r);
|
|
568
602
|
}
|
|
569
603
|
buildSubjectCard(e) {
|
|
570
604
|
if (this.subjectBuilt) return;
|
|
571
605
|
const i = e.subject, s = this.cfg.subject, a = (i == null ? void 0 : i.title) ?? (s == null ? void 0 : s.title);
|
|
572
606
|
if (!a) return;
|
|
573
607
|
this.subjectBuilt = !0, this.subjectCard.replaceChildren(), this.subjectCard.append(t("div", "ocw-subject-title", a)), s != null && s.subtitle && this.subjectCard.append(t("div", "ocw-subject-sub", s.subtitle));
|
|
574
|
-
const
|
|
575
|
-
if (i) for (const [b, d] of Object.entries(i.fields))
|
|
576
|
-
else for (const b of (s == null ? void 0 : s.tags) ?? [])
|
|
577
|
-
|
|
608
|
+
const r = t("div", "ocw-tags");
|
|
609
|
+
if (i) for (const [b, d] of Object.entries(i.fields)) r.append(t("span", "ocw-tag", `${b}: ${d}`));
|
|
610
|
+
else for (const b of (s == null ? void 0 : s.tags) ?? []) r.append(t("span", "ocw-tag", b));
|
|
611
|
+
r.childNodes.length && this.subjectCard.append(r);
|
|
578
612
|
const f = (i == null ? void 0 : i.state) ?? (s == null ? void 0 : s.status);
|
|
579
613
|
f && (this.statusBadge.textContent = f, this.statusBadge.style.display = "inline-flex");
|
|
580
614
|
}
|
|
@@ -590,12 +624,12 @@ Message: ${c.value}`), this.offlinePanel.replaceChildren(t("div", "ocw-offline-t
|
|
|
590
624
|
return new Promise((i) => {
|
|
591
625
|
const s = t("div", "ocw-modal"), a = t("div", "ocw-modal-card");
|
|
592
626
|
a.append(t("div", "ocw-modal-title", e)), a.append(t("div", "ocw-modal-body", `Confirm “${e}”?`));
|
|
593
|
-
const
|
|
594
|
-
s.remove(), i(
|
|
627
|
+
const r = t("div", "ocw-modal-actions"), f = t("button", "ocw-modal-cancel", "Cancel"), b = t("button", "ocw-modal-ok", "Confirm"), d = (h) => {
|
|
628
|
+
s.remove(), i(h);
|
|
595
629
|
};
|
|
596
|
-
f.addEventListener("click", () => d(!1)), b.addEventListener("click", () => d(!0)), s.addEventListener("click", (
|
|
597
|
-
|
|
598
|
-
}),
|
|
630
|
+
f.addEventListener("click", () => d(!1)), b.addEventListener("click", () => d(!0)), s.addEventListener("click", (h) => {
|
|
631
|
+
h.target === s && d(!1);
|
|
632
|
+
}), r.append(f, b), a.append(r), s.append(a), this.root.append(s), b.focus();
|
|
599
633
|
});
|
|
600
634
|
}
|
|
601
635
|
/** Inline form for a form-effect action: typed inputs (date picker, number,
|
|
@@ -606,54 +640,54 @@ Message: ${c.value}`), this.offlinePanel.replaceChildren(t("div", "ocw-offline-t
|
|
|
606
640
|
const i = t("div", "ocw-form");
|
|
607
641
|
i.append(t("div", "ocw-form-title", e.icon ? `${e.icon} ${e.label}` : e.label));
|
|
608
642
|
const s = /* @__PURE__ */ new Map();
|
|
609
|
-
for (const
|
|
610
|
-
const
|
|
611
|
-
if (
|
|
612
|
-
const
|
|
613
|
-
|
|
614
|
-
for (const u of
|
|
643
|
+
for (const h of e.input ?? []) {
|
|
644
|
+
const y = t("label", "ocw-form-row");
|
|
645
|
+
if (y.append(t("span", "ocw-form-lbl", h.label)), h.type === "select" && ((b = h.options) != null && b.length)) {
|
|
646
|
+
const c = t("select", "ocw-form-input");
|
|
647
|
+
h.required || c.append(t("option", void 0, "— select —"));
|
|
648
|
+
for (const u of h.options) {
|
|
615
649
|
const l = t("option");
|
|
616
|
-
l.value = u, l.textContent = u,
|
|
650
|
+
l.value = u, l.textContent = u, c.append(l);
|
|
617
651
|
}
|
|
618
|
-
|
|
652
|
+
h.required && (c.required = !0), y.append(c), s.set(h.name, c);
|
|
619
653
|
} else {
|
|
620
|
-
const
|
|
621
|
-
|
|
654
|
+
const c = t("input", "ocw-form-input");
|
|
655
|
+
c.type = h.type === "number" ? "number" : h.type === "date" ? "datetime-local" : "text", h.required && (c.required = !0), y.append(c), s.set(h.name, c);
|
|
622
656
|
}
|
|
623
|
-
i.append(
|
|
657
|
+
i.append(y);
|
|
624
658
|
}
|
|
625
|
-
const a = t("div", "ocw-form-actions"),
|
|
626
|
-
|
|
627
|
-
const
|
|
628
|
-
for (const [
|
|
629
|
-
if (
|
|
630
|
-
|
|
659
|
+
const a = t("div", "ocw-form-actions"), r = t("button", "ocw-form-cancel", "Cancel"), f = t("button", "ocw-form-submit", "Send");
|
|
660
|
+
r.addEventListener("click", () => this.formHost.replaceChildren()), f.addEventListener("click", () => {
|
|
661
|
+
const h = {};
|
|
662
|
+
for (const [y, c] of s) {
|
|
663
|
+
if (c.required && !c.value) {
|
|
664
|
+
c.style.borderColor = "#e5484d";
|
|
631
665
|
return;
|
|
632
666
|
}
|
|
633
|
-
|
|
667
|
+
h[y] = c.type === "number" ? Number(c.value) : c.value;
|
|
634
668
|
}
|
|
635
|
-
this.formHost.replaceChildren(), this.h.onInvoke(e.id,
|
|
636
|
-
}), a.append(
|
|
669
|
+
this.formHost.replaceChildren(), this.h.onInvoke(e.id, h);
|
|
670
|
+
}), a.append(r, f), i.append(a), this.formHost.append(i), (d = s.values().next().value) == null || d.focus();
|
|
637
671
|
}
|
|
638
672
|
messageEl(e, i) {
|
|
639
|
-
var
|
|
673
|
+
var c;
|
|
640
674
|
if (e.senderRole === "system") {
|
|
641
675
|
const u = t("div", "ocw-sys");
|
|
642
|
-
return u.textContent = e.deletedAt ? "message deleted" :
|
|
676
|
+
return u.textContent = e.deletedAt ? "message deleted" : X(e.content), u;
|
|
643
677
|
}
|
|
644
|
-
const s = e.senderId === this.me, a = !!e.internal,
|
|
645
|
-
!s && !a &&
|
|
678
|
+
const s = e.senderId === this.me, a = !!e.internal, r = t("div", `ocw-row ${a ? "ocw-note mine" : s ? "mine" : "theirs"} ${e.senderRole === "bot" ? "ocw-bot" : ""}`);
|
|
679
|
+
!s && !a && r.append(t("div", "ocw-dot", e.senderRole === "bot" ? "🤖" : "🧑"));
|
|
646
680
|
const f = t("div"), b = t("div", "ocw-bubble-wrap");
|
|
647
681
|
if (e.replyToId) {
|
|
648
682
|
const u = t("div", "ocw-reply-to", "↩ replying to a message");
|
|
649
683
|
u.style.cssText = "font-size:11px;color:var(--ocw-mut);margin-bottom:2px;font-style:italic", f.append(u);
|
|
650
684
|
}
|
|
651
685
|
const d = t("div", "ocw-bubble");
|
|
652
|
-
let
|
|
686
|
+
let h = null;
|
|
653
687
|
if (e.deletedAt) d.append(t("span", "ocw-deleted", "message deleted"));
|
|
654
688
|
else if (e.content.kind === "attachment") {
|
|
655
689
|
const u = e.content;
|
|
656
|
-
if ((
|
|
690
|
+
if ((c = u.mime) != null && c.startsWith("image/")) {
|
|
657
691
|
const l = document.createElement("img");
|
|
658
692
|
l.src = u.url, l.alt = u.name ?? "image", l.style.cssText = "max-width:220px;max-height:160px;border-radius:10px;display:block;cursor:pointer", l.addEventListener("click", () => window.open(u.url, "_blank")), d.append(l);
|
|
659
693
|
} else {
|
|
@@ -663,34 +697,34 @@ Message: ${c.value}`), this.offlinePanel.replaceChildren(t("div", "ocw-offline-t
|
|
|
663
697
|
} else if (e.content.kind === "appointment") {
|
|
664
698
|
const u = e.content, l = t("div", "ocw-appt");
|
|
665
699
|
l.append(t("div", "ocw-appt-title", `📅 ${u.title}`)), l.append(t("div", "ocw-appt-time", new Date(u.startIso).toLocaleString() + " – " + new Date(u.endIso).toLocaleTimeString())), u.location && l.append(t("div", "ocw-appt-loc", `📍 ${u.location}`)), u.description && l.append(t("div", "ocw-appt-desc", u.description));
|
|
666
|
-
const
|
|
700
|
+
const T = t("div", "ocw-appt-links"), m = document.createElement("a");
|
|
667
701
|
m.href = u.googleUrl, m.target = "_blank", m.rel = "noopener", m.className = "ocw-appt-btn", m.textContent = "📅 Add to Google Calendar";
|
|
668
|
-
const
|
|
669
|
-
|
|
702
|
+
const w = document.createElement("a");
|
|
703
|
+
w.href = u.icalUrl, w.download = `${u.title}.ics`, w.className = "ocw-appt-btn ocw-appt-btn-sec", w.textContent = "🍎 Apple / iCal", T.append(m, w), l.append(T), d.append(l);
|
|
670
704
|
} else
|
|
671
|
-
|
|
672
|
-
if (b.append(d), !s && !a && this.h.onTranslate && e.content.kind === "text" && !e.deletedAt && e.seq > 0 &&
|
|
705
|
+
h = document.createTextNode(X(e.content)), d.append(h), e.editedAt && d.append(t("span", "ocw-edited", "(edited)"));
|
|
706
|
+
if (b.append(d), !s && !a && this.h.onTranslate && e.content.kind === "text" && !e.deletedAt && e.seq > 0 && h) {
|
|
673
707
|
const u = e.content.text;
|
|
674
708
|
if (u.trim()) {
|
|
675
709
|
const l = t("button", "ocw-translate-btn", "🌐");
|
|
676
|
-
l.type = "button", l.title = "Translate", l.addEventListener("click", (
|
|
677
|
-
if (
|
|
678
|
-
this.showingTranslation.delete(e.id),
|
|
710
|
+
l.type = "button", l.title = "Translate", l.addEventListener("click", (T) => {
|
|
711
|
+
if (T.stopPropagation(), this.showingTranslation.has(e.id)) {
|
|
712
|
+
this.showingTranslation.delete(e.id), h.textContent = u, l.textContent = "🌐", l.title = "Translate";
|
|
679
713
|
return;
|
|
680
714
|
}
|
|
681
715
|
const m = this.translationCache.get(e.id);
|
|
682
716
|
if (m !== void 0) {
|
|
683
|
-
this.showingTranslation.add(e.id),
|
|
717
|
+
this.showingTranslation.add(e.id), h.textContent = m, l.textContent = "↩", l.title = "Show original";
|
|
684
718
|
return;
|
|
685
719
|
}
|
|
686
|
-
l.textContent = "⏳", this.h.onTranslate(u).then((
|
|
687
|
-
if (
|
|
720
|
+
l.textContent = "⏳", this.h.onTranslate(u).then((w) => {
|
|
721
|
+
if (w === null) {
|
|
688
722
|
l.textContent = "⚠️", l.title = "Translation unavailable", setTimeout(() => {
|
|
689
723
|
l.textContent = "🌐", l.title = "Translate";
|
|
690
724
|
}, 1500);
|
|
691
725
|
return;
|
|
692
726
|
}
|
|
693
|
-
this.translationCache.set(e.id,
|
|
727
|
+
this.translationCache.set(e.id, w), this.showingTranslation.add(e.id), h.textContent = w, l.textContent = "↩", l.title = "Show original";
|
|
694
728
|
});
|
|
695
729
|
}), b.append(l);
|
|
696
730
|
}
|
|
@@ -699,31 +733,31 @@ Message: ${c.value}`), this.offlinePanel.replaceChildren(t("div", "ocw-offline-t
|
|
|
699
733
|
const u = t("div", "ocw-msg-menu");
|
|
700
734
|
if (this.h.onEdit) {
|
|
701
735
|
const l = t("button", void 0, "✏️");
|
|
702
|
-
l.title = "Edit", l.addEventListener("click", (
|
|
703
|
-
|
|
704
|
-
const m =
|
|
705
|
-
|
|
706
|
-
const
|
|
707
|
-
|
|
708
|
-
const
|
|
709
|
-
|
|
710
|
-
const
|
|
711
|
-
|
|
736
|
+
l.title = "Edit", l.addEventListener("click", (T) => {
|
|
737
|
+
T.stopPropagation();
|
|
738
|
+
const m = X(e.content), w = document.createElement("textarea");
|
|
739
|
+
w.value = m, w.rows = Math.min(4, Math.ceil(m.length / 40) + 1), w.style.cssText = "width:100%;resize:vertical;border:1px solid var(--ocw-accent);border-radius:8px;padding:6px 10px;font:inherit;font-size:14px;background:#fff;color:#1c1b1a;box-sizing:border-box";
|
|
740
|
+
const k = t("button", "ocw-form-submit", "Save");
|
|
741
|
+
k.style.cssText = "margin-top:6px;padding:5px 14px;font-size:13px";
|
|
742
|
+
const E = t("button", "ocw-form-cancel", "Cancel");
|
|
743
|
+
E.style.cssText = "margin-top:6px;padding:5px 10px;font-size:13px";
|
|
744
|
+
const I = t("div");
|
|
745
|
+
I.style.cssText = "display:flex;gap:6px;justify-content:flex-end", I.append(E, k);
|
|
712
746
|
const A = t("div");
|
|
713
|
-
A.append(
|
|
714
|
-
const
|
|
715
|
-
|
|
716
|
-
const z =
|
|
717
|
-
z && z !== m && this.h.onEdit(e.id, z),
|
|
718
|
-
}),
|
|
719
|
-
z.key === "Enter" && !z.shiftKey && (z.preventDefault(),
|
|
747
|
+
A.append(w, I), d.replaceChildren(A), w.focus(), w.select();
|
|
748
|
+
const $ = () => d.replaceChildren(h ?? document.createTextNode(m));
|
|
749
|
+
E.addEventListener("click", $), k.addEventListener("click", () => {
|
|
750
|
+
const z = w.value.trim();
|
|
751
|
+
z && z !== m && this.h.onEdit(e.id, z), $();
|
|
752
|
+
}), w.addEventListener("keydown", (z) => {
|
|
753
|
+
z.key === "Enter" && !z.shiftKey && (z.preventDefault(), k.click()), z.key === "Escape" && $();
|
|
720
754
|
});
|
|
721
755
|
}), u.append(l);
|
|
722
756
|
}
|
|
723
757
|
if (this.h.onDelete) {
|
|
724
758
|
const l = t("button", "del", "🗑");
|
|
725
|
-
l.title = "Delete", l.addEventListener("click", (
|
|
726
|
-
|
|
759
|
+
l.title = "Delete", l.addEventListener("click", (T) => {
|
|
760
|
+
T.stopPropagation(), this.h.onDelete(e.id);
|
|
727
761
|
}), u.append(l);
|
|
728
762
|
}
|
|
729
763
|
b.append(u);
|
|
@@ -731,38 +765,40 @@ Message: ${c.value}`), this.offlinePanel.replaceChildren(t("div", "ocw-offline-t
|
|
|
731
765
|
if (f.append(b), this.h.onReact && !e.deletedAt && e.seq > 0) {
|
|
732
766
|
const u = t("div", "ocw-react-wrap"), l = t("div", "ocw-react");
|
|
733
767
|
if (e.reactions && Object.keys(e.reactions).length)
|
|
734
|
-
for (const [
|
|
735
|
-
const
|
|
736
|
-
|
|
737
|
-
var
|
|
738
|
-
return (A = (
|
|
739
|
-
}), l.append(
|
|
768
|
+
for (const [w, k] of Object.entries(e.reactions)) {
|
|
769
|
+
const E = t("button", `ocw-react-pill${k.includes(this.me) ? " mine" : ""}`, `${w} ${k.length}`);
|
|
770
|
+
E.addEventListener("click", () => {
|
|
771
|
+
var I, A;
|
|
772
|
+
return (A = (I = this.h).onReact) == null ? void 0 : A.call(I, e.id, w, k.includes(this.me));
|
|
773
|
+
}), l.append(E);
|
|
740
774
|
}
|
|
741
|
-
const
|
|
742
|
-
for (const
|
|
743
|
-
const
|
|
744
|
-
|
|
745
|
-
var A,
|
|
746
|
-
|
|
747
|
-
const
|
|
748
|
-
(
|
|
749
|
-
}), m.append(
|
|
775
|
+
const T = t("button", "ocw-react-btn", "+"), m = t("div", "ocw-react-picker");
|
|
776
|
+
for (const w of Ee) {
|
|
777
|
+
const k = t("button", void 0, w);
|
|
778
|
+
k.addEventListener("click", (E) => {
|
|
779
|
+
var A, $, z, q;
|
|
780
|
+
E.stopPropagation();
|
|
781
|
+
const I = ($ = (A = e.reactions) == null ? void 0 : A[w]) == null ? void 0 : $.includes(this.me);
|
|
782
|
+
(q = (z = this.h).onReact) == null || q.call(z, e.id, w, !!I), m.style.display = "none";
|
|
783
|
+
}), m.append(k);
|
|
750
784
|
}
|
|
751
|
-
m.style.display = "none",
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
m.style.display = "none"
|
|
755
|
-
|
|
785
|
+
m.style.display = "none", T.addEventListener("click", (w) => {
|
|
786
|
+
w.stopPropagation();
|
|
787
|
+
const k = m.style.display === "none";
|
|
788
|
+
m.style.display = k ? "flex" : "none", k && document.addEventListener("click", () => {
|
|
789
|
+
m.style.display = "none";
|
|
790
|
+
}, { once: !0 });
|
|
791
|
+
}), l.append(T), u.append(l, m), f.append(u);
|
|
756
792
|
} else e.reactions && Object.keys(e.reactions).length && f.append(t("div", "ocw-react", Object.entries(e.reactions).map(([u, l]) => `${u}${l.length}`).join(" ")));
|
|
757
|
-
const
|
|
793
|
+
const y = t("div", "ocw-time ocw-meta", $e(e.ts));
|
|
758
794
|
if (s && e.status) {
|
|
759
|
-
const u = t("span", `ocw-tick${e.status === "read" ? " read" : e.status === "delivered" ? " delivered" : ""}`,
|
|
760
|
-
|
|
795
|
+
const u = t("span", `ocw-tick${e.status === "read" ? " read" : e.status === "delivered" ? " delivered" : ""}`, Me(e.status));
|
|
796
|
+
y.append(u);
|
|
761
797
|
}
|
|
762
|
-
return s && e.seq > 0 && i.lastReadByOthers >= e.seq &&
|
|
798
|
+
return s && e.seq > 0 && i.lastReadByOthers >= e.seq && y.append(t("span", "ocw-seen", " · Seen")), f.append(y), r.append(f), r;
|
|
763
799
|
}
|
|
764
800
|
}
|
|
765
|
-
function
|
|
801
|
+
function Me(o) {
|
|
766
802
|
switch (o) {
|
|
767
803
|
case "read":
|
|
768
804
|
return "✓✓";
|
|
@@ -774,35 +810,44 @@ function ze(o) {
|
|
|
774
810
|
return "🕓";
|
|
775
811
|
}
|
|
776
812
|
}
|
|
777
|
-
const
|
|
778
|
-
function
|
|
813
|
+
const O = /* @__PURE__ */ new WeakMap(), W = /* @__PURE__ */ new Map();
|
|
814
|
+
function ce(o) {
|
|
779
815
|
return `relay-launcher::${o.profileId}::${o.subjectId ?? ""}`;
|
|
780
816
|
}
|
|
781
|
-
|
|
817
|
+
let N = null;
|
|
818
|
+
function Re() {
|
|
819
|
+
if (N && N.state !== "closed") return N;
|
|
820
|
+
try {
|
|
821
|
+
return N = new AudioContext(), N;
|
|
822
|
+
} catch {
|
|
823
|
+
return null;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
function Ne(o) {
|
|
782
827
|
var e;
|
|
783
|
-
(e =
|
|
828
|
+
(e = O.get(o)) == null || e.close(), O.delete(o);
|
|
784
829
|
}
|
|
785
|
-
function
|
|
786
|
-
var
|
|
787
|
-
|
|
788
|
-
const e =
|
|
830
|
+
function _e(o) {
|
|
831
|
+
var ee, te, oe, ne, ie;
|
|
832
|
+
O.has(o.el) && (O.get(o.el).close(), O.delete(o.el)), o.launcher && ((ee = W.get(ce(o))) == null || ee.close());
|
|
833
|
+
const e = ge();
|
|
789
834
|
let i, s = !1;
|
|
790
|
-
const a = o.token ?? o.userId ?? e,
|
|
791
|
-
let d = new
|
|
792
|
-
const
|
|
793
|
-
let
|
|
835
|
+
const a = o.token ?? o.userId ?? e, r = a !== e ? e : void 0, { wsUrl: f, httpBase: b } = me(o.url, o.apiUrl);
|
|
836
|
+
let d = new ke(a);
|
|
837
|
+
const h = o.subjectId ? `${a}::${o.subjectId}` : a, y = new ye(h);
|
|
838
|
+
let c, u = !1, l = null, T = null, m = null;
|
|
794
839
|
!o.launcher && !o.el.style.height && o.el.clientHeight === 0 && (o.el.style.width = o.el.style.width || "100%", o.el.style.height = "600px");
|
|
795
|
-
for (const n of
|
|
796
|
-
let
|
|
840
|
+
for (const n of y.load()) d.addOptimistic(n.clientMsgId, n.content);
|
|
841
|
+
let w = null, k = null, E = 0, I = !o.launcher;
|
|
797
842
|
if (o.launcher) {
|
|
798
843
|
const p = (o.position ?? "bottom-right").includes("right");
|
|
799
|
-
|
|
800
|
-
const g = document.createElement("div"),
|
|
801
|
-
g.style.cssText =
|
|
844
|
+
w = document.createElement("div"), w.style.cssText = `position:fixed;${p ? "right:20px" : "left:20px"};bottom:20px;z-index:9999;display:flex;flex-direction:column;align-items:${p ? "flex-end" : "flex-start"};gap:12px`;
|
|
845
|
+
const g = document.createElement("div"), P = typeof window < "u" && typeof window.matchMedia == "function" ? window.matchMedia("(max-width: 479px)") : null, U = (R) => {
|
|
846
|
+
o.el.classList.toggle("ocw-fs", R), g.style.cssText = R ? [
|
|
802
847
|
"position:fixed",
|
|
803
848
|
"inset:0",
|
|
804
849
|
"width:100%",
|
|
805
|
-
"height:
|
|
850
|
+
"height:100dvh",
|
|
806
851
|
"border-radius:0",
|
|
807
852
|
"overflow:hidden",
|
|
808
853
|
"box-shadow:none",
|
|
@@ -813,8 +858,8 @@ function Be(o) {
|
|
|
813
858
|
"opacity:0",
|
|
814
859
|
"z-index:9998"
|
|
815
860
|
].join(";") : [
|
|
816
|
-
"width:380px",
|
|
817
|
-
"height:600px",
|
|
861
|
+
"width:min(380px, calc(100vw - 40px))",
|
|
862
|
+
"height:min(600px, calc(100dvh - 108px))",
|
|
818
863
|
"border-radius:16px",
|
|
819
864
|
"overflow:hidden",
|
|
820
865
|
"box-shadow:0 8px 40px rgba(0,0,0,.18)",
|
|
@@ -827,86 +872,95 @@ function Be(o) {
|
|
|
827
872
|
"transform:scale(.95)"
|
|
828
873
|
].join(";");
|
|
829
874
|
};
|
|
830
|
-
|
|
831
|
-
const
|
|
832
|
-
|
|
833
|
-
const
|
|
834
|
-
|
|
875
|
+
U((P == null ? void 0 : P.matches) ?? !1);
|
|
876
|
+
const F = (R) => U(R.matches);
|
|
877
|
+
P == null || P.addEventListener("change", F), l = P, T = F, o.el.style.cssText = "width:100%;height:100%;overflow:hidden", g.append(o.el);
|
|
878
|
+
const K = '<svg viewBox="0 0 24 24" width="26" height="26" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>', Y = '<svg viewBox="0 0 24 24" width="22" height="22" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"/></svg>', B = document.createElement("button");
|
|
879
|
+
B.type = "button", B.style.cssText = [
|
|
835
880
|
"width:56px;height:56px;border-radius:50%",
|
|
836
881
|
`background:${o.accent ?? "#4F63F5"}`,
|
|
837
|
-
"color:#fff;border:none;
|
|
882
|
+
"color:#fff;border:none;cursor:pointer",
|
|
838
883
|
"box-shadow:0 4px 16px rgba(0,0,0,.25)",
|
|
839
884
|
"position:relative;flex:none",
|
|
885
|
+
"display:flex;align-items:center;justify-content:center",
|
|
840
886
|
"transition:transform .15s"
|
|
841
|
-
].join(";"),
|
|
842
|
-
|
|
843
|
-
},
|
|
844
|
-
|
|
845
|
-
},
|
|
846
|
-
const
|
|
847
|
-
|
|
887
|
+
].join(";"), B.onmouseenter = () => {
|
|
888
|
+
B.style.transform = "scale(1.08)";
|
|
889
|
+
}, B.onmouseleave = () => {
|
|
890
|
+
B.style.transform = "scale(1)";
|
|
891
|
+
}, k = document.createElement("span"), k.style.cssText = "position:absolute;top:-4px;right:-4px;background:#ef4444;color:#fff;border-radius:50%;width:20px;height:20px;font-size:11px;font-weight:700;display:none;align-items:center;justify-content:center";
|
|
892
|
+
const G = () => {
|
|
893
|
+
B.innerHTML = I ? Y : K, B.setAttribute("aria-label", I ? "Close chat" : "Open chat"), B.setAttribute("aria-expanded", String(I)), B.append(k);
|
|
894
|
+
};
|
|
895
|
+
G(), w.append(g, B), document.body.append(w);
|
|
896
|
+
const se = (R) => {
|
|
897
|
+
R ? (g.style.display = "flex", requestAnimationFrame(() => {
|
|
848
898
|
g.style.opacity = "1", g.style.transform = "scale(1)";
|
|
849
899
|
})) : (g.style.opacity = "0", g.style.transform = "scale(.95)", setTimeout(() => {
|
|
850
|
-
|
|
900
|
+
I || (g.style.display = "none");
|
|
851
901
|
}, 180));
|
|
852
902
|
};
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
}),
|
|
856
|
-
|
|
857
|
-
});
|
|
903
|
+
B.addEventListener("click", () => {
|
|
904
|
+
I = !I, se(I), G(), I && (E = 0, k && (k.style.display = "none"));
|
|
905
|
+
}), m = (R) => {
|
|
906
|
+
R.key === "Escape" && I && (I = !1, se(!1), G());
|
|
907
|
+
}, document.addEventListener("keydown", m);
|
|
858
908
|
}
|
|
859
|
-
const
|
|
860
|
-
|
|
861
|
-
},
|
|
909
|
+
const A = () => {
|
|
910
|
+
I || (E++, k && (k.textContent = String(E), k.style.display = "flex"));
|
|
911
|
+
}, $ = () => {
|
|
862
912
|
try {
|
|
863
|
-
const n =
|
|
913
|
+
const n = Re();
|
|
914
|
+
if (!n) return;
|
|
915
|
+
n.state === "suspended" && n.resume().catch(() => {
|
|
916
|
+
});
|
|
917
|
+
const p = n.createOscillator(), g = n.createGain();
|
|
864
918
|
p.connect(g), g.connect(n.destination), p.frequency.setValueAtTime(880, n.currentTime), p.frequency.exponentialRampToValueAtTime(440, n.currentTime + 0.15), g.gain.setValueAtTime(0.3, n.currentTime), g.gain.exponentialRampToValueAtTime(1e-3, n.currentTime + 0.3), p.start(), p.stop(n.currentTime + 0.3);
|
|
865
919
|
} catch {
|
|
866
920
|
}
|
|
867
|
-
},
|
|
868
|
-
for (;
|
|
869
|
-
const p =
|
|
870
|
-
|
|
921
|
+
}, z = [], q = (n) => {
|
|
922
|
+
for (; z.length; ) {
|
|
923
|
+
const p = z.shift();
|
|
924
|
+
y.add({ clientMsgId: p.clientMsgId, content: p.content, ts: Date.now() }), C.send({ type: "send", conversationId: n, clientMsgId: p.clientMsgId, content: p.content });
|
|
871
925
|
}
|
|
872
926
|
};
|
|
873
|
-
let
|
|
874
|
-
const
|
|
875
|
-
let
|
|
876
|
-
const
|
|
877
|
-
let
|
|
878
|
-
const
|
|
879
|
-
|
|
880
|
-
|
|
927
|
+
let C;
|
|
928
|
+
const j = new Te(`ocw-e2e-${o.profileId}`);
|
|
929
|
+
let D = !1;
|
|
930
|
+
const x = [], S = [];
|
|
931
|
+
let M = !1;
|
|
932
|
+
const V = (n, p) => {
|
|
933
|
+
j.sealText(p).then((g) => {
|
|
934
|
+
c && C.send({ type: "send", conversationId: c, clientMsgId: n, content: g });
|
|
881
935
|
});
|
|
882
|
-
},
|
|
883
|
-
|
|
884
|
-
|
|
936
|
+
}, le = (n, p, g) => {
|
|
937
|
+
j.sealText(p, g).then((P) => {
|
|
938
|
+
c && C.send({ type: "send", conversationId: c, clientMsgId: n, content: P });
|
|
885
939
|
});
|
|
886
|
-
},
|
|
887
|
-
for (;
|
|
888
|
-
const n =
|
|
889
|
-
|
|
940
|
+
}, de = () => {
|
|
941
|
+
for (; x.length; ) {
|
|
942
|
+
const n = x.shift();
|
|
943
|
+
V(n.clientMsgId, n.text);
|
|
890
944
|
}
|
|
891
|
-
for (;
|
|
892
|
-
const n =
|
|
893
|
-
|
|
945
|
+
for (; S.length; ) {
|
|
946
|
+
const n = S.shift();
|
|
947
|
+
V(n.clientMsgId, n.text);
|
|
894
948
|
}
|
|
895
|
-
},
|
|
896
|
-
|
|
897
|
-
},
|
|
898
|
-
|
|
899
|
-
const
|
|
949
|
+
}, pe = (n) => {
|
|
950
|
+
C.send({ type: "fetchPrekey", targetUserId: n });
|
|
951
|
+
}, he = o.i18n ?? {}, ue = ["ar", "he", "fa", "ur"], fe = typeof navigator < "u" ? (navigator.language ?? "").slice(0, 2).toLowerCase() : "";
|
|
952
|
+
ue.includes(fe) && !o.el.dir && (o.el.dir = "rtl", o.el.style.fontFamily = o.el.style.fontFamily || "Tahoma,Arial,system-ui,sans-serif");
|
|
953
|
+
const J = new ze(), Q = `oc_prechat_${o.profileId}_${a.slice(-8)}`, L = new Be(o.el, a, {
|
|
900
954
|
onSend(n) {
|
|
901
955
|
const p = `cm_${Math.random().toString(36).slice(2)}`, g = { kind: "text", text: n };
|
|
902
|
-
d.addOptimistic(p, g),
|
|
956
|
+
d.addOptimistic(p, g), L.render(d), d.e2e ? j.ready ? V(p, n) : M ? S.push({ clientMsgId: p, text: n }) : (x.push({ clientMsgId: p, text: n }), d.assignedAgentId && pe(d.assignedAgentId)) : c ? (y.add({ clientMsgId: p, content: g, ts: Date.now() }), C.send({ type: "send", conversationId: c, clientMsgId: p, content: g })) : z.push({ clientMsgId: p, content: g });
|
|
903
957
|
},
|
|
904
958
|
async onAttach(n) {
|
|
905
|
-
if (!
|
|
959
|
+
if (!c) return;
|
|
906
960
|
const p = `${b}/upload?name=${encodeURIComponent(n.name)}`, g = `cm_${Math.random().toString(36).slice(2)}`;
|
|
907
|
-
d.addOptimistic(g, { kind: "text", text: `📎 Uploading ${n.name}…` }),
|
|
961
|
+
d.addOptimistic(g, { kind: "text", text: `📎 Uploading ${n.name}…` }), L.render(d);
|
|
908
962
|
try {
|
|
909
|
-
const
|
|
963
|
+
const P = await fetch(p, {
|
|
910
964
|
method: "POST",
|
|
911
965
|
// Use the resolved connection token (a signed JWT, an explicit userId,
|
|
912
966
|
// or the anonymous persistent uid) — NOT just opts.token. The server
|
|
@@ -916,25 +970,25 @@ function Be(o) {
|
|
|
916
970
|
headers: { "content-type": n.type, authorization: `Bearer ${a}` },
|
|
917
971
|
body: n
|
|
918
972
|
});
|
|
919
|
-
if (!
|
|
920
|
-
const { url:
|
|
921
|
-
|
|
922
|
-
} catch (
|
|
923
|
-
d.addOptimistic(g, { kind: "text", text: `⚠️ Upload failed: ${
|
|
973
|
+
if (!P.ok) throw new Error(`Upload failed: ${P.status}`);
|
|
974
|
+
const { url: U, name: F, mime: K, size: Y } = await P.json();
|
|
975
|
+
C.send({ type: "send", conversationId: c, clientMsgId: g, content: { kind: "attachment", url: U, name: F, mime: K, size: Y } });
|
|
976
|
+
} catch (P) {
|
|
977
|
+
d.addOptimistic(g, { kind: "text", text: `⚠️ Upload failed: ${P.message}` }), L.render(d);
|
|
924
978
|
}
|
|
925
979
|
},
|
|
926
980
|
onInvoke(n, p) {
|
|
927
|
-
|
|
981
|
+
c && C.send({ type: "invoke", conversationId: c, actionId: n, clientInvokeId: `iv_${Math.random().toString(36).slice(2)}`, ...p ? { inputs: p } : {} });
|
|
928
982
|
},
|
|
929
983
|
onTyping(n, p) {
|
|
930
|
-
|
|
984
|
+
c && C.send({ type: "typing", conversationId: c, isTyping: n, ...p ? { preview: p } : {} });
|
|
931
985
|
},
|
|
932
986
|
onPreChat(n) {
|
|
933
987
|
try {
|
|
934
|
-
localStorage.setItem(
|
|
988
|
+
localStorage.setItem(Q, "1");
|
|
935
989
|
} catch {
|
|
936
990
|
}
|
|
937
|
-
|
|
991
|
+
C.send({
|
|
938
992
|
type: "open",
|
|
939
993
|
profileId: o.profileId,
|
|
940
994
|
...o.subjectId ? { subjectId: o.subjectId } : {},
|
|
@@ -948,39 +1002,39 @@ function Be(o) {
|
|
|
948
1002
|
}
|
|
949
1003
|
});
|
|
950
1004
|
const p = n.callback ? `📞 Call-back requested${n.phone ? `: ${n.phone}` : ""}${n.topic ? ` — ${n.topic}` : ""}` : n.topic ? `Topic: ${n.topic}` : "";
|
|
951
|
-
p &&
|
|
1005
|
+
p && c && !d.e2e && C.send({ type: "send", conversationId: c, clientMsgId: `pc_${Math.random().toString(36).slice(2, 12)}`, content: { kind: "text", text: p } });
|
|
952
1006
|
},
|
|
953
1007
|
onDeflectQuery(n) {
|
|
954
1008
|
if (s) return;
|
|
955
1009
|
clearTimeout(i);
|
|
956
1010
|
const p = n.trim();
|
|
957
1011
|
if (p.length < 3) {
|
|
958
|
-
|
|
1012
|
+
L.hideDeflection();
|
|
959
1013
|
return;
|
|
960
1014
|
}
|
|
961
1015
|
i = setTimeout(() => {
|
|
962
|
-
fetch(`${b}/kb/search?profileId=${encodeURIComponent(o.profileId)}&q=${encodeURIComponent(p.slice(0, 200))}`).then((g) => g.ok ? g.json() : { articles: [] }).then((g) =>
|
|
1016
|
+
fetch(`${b}/kb/search?profileId=${encodeURIComponent(o.profileId)}&q=${encodeURIComponent(p.slice(0, 200))}`).then((g) => g.ok ? g.json() : { articles: [] }).then((g) => L.showDeflection(g.articles ?? [])).catch(() => L.hideDeflection());
|
|
963
1017
|
}, 350);
|
|
964
1018
|
},
|
|
965
1019
|
onReadUpTo(n) {
|
|
966
|
-
|
|
1020
|
+
c && C.send({ type: "read", conversationId: c, seq: n });
|
|
967
1021
|
},
|
|
968
1022
|
onLoadMore() {
|
|
969
|
-
if (!
|
|
1023
|
+
if (!c || !d.e2e) return;
|
|
970
1024
|
const n = d.messages()[0];
|
|
971
|
-
n &&
|
|
1025
|
+
n && C.send({ type: "history", conversationId: c, beforeSeq: n.seq, limit: 20 });
|
|
972
1026
|
},
|
|
973
1027
|
onEdit(n, p) {
|
|
974
|
-
|
|
1028
|
+
c && C.send({ type: "edit", conversationId: c, messageId: n, content: { kind: "text", text: p } });
|
|
975
1029
|
},
|
|
976
1030
|
onDelete(n) {
|
|
977
|
-
|
|
1031
|
+
c && C.send({ type: "delete", conversationId: c, messageId: n });
|
|
978
1032
|
},
|
|
979
1033
|
onReact(n, p, g) {
|
|
980
|
-
|
|
1034
|
+
c && C.send({ type: "react", conversationId: c, messageId: n, emoji: p, remove: g });
|
|
981
1035
|
},
|
|
982
1036
|
onCsat(n) {
|
|
983
|
-
|
|
1037
|
+
c && fetch(`${b}/conversations/${c}/csat`, {
|
|
984
1038
|
method: "POST",
|
|
985
1039
|
headers: { "Content-Type": "application/json", Authorization: `Bearer ${a}` },
|
|
986
1040
|
body: JSON.stringify({ score: n })
|
|
@@ -988,10 +1042,10 @@ function Be(o) {
|
|
|
988
1042
|
});
|
|
989
1043
|
},
|
|
990
1044
|
onAnnotate(n) {
|
|
991
|
-
|
|
1045
|
+
c && C.send({ type: "annotate", conversationId: c, stroke: n });
|
|
992
1046
|
},
|
|
993
1047
|
onAnnotateClear() {
|
|
994
|
-
|
|
1048
|
+
c && C.send({ type: "annotate_clear", conversationId: c });
|
|
995
1049
|
},
|
|
996
1050
|
...o.translateLang ? {
|
|
997
1051
|
async onTranslate(n) {
|
|
@@ -1014,102 +1068,102 @@ function Be(o) {
|
|
|
1014
1068
|
...o.subject ? { subject: o.subject } : {},
|
|
1015
1069
|
...o.quickReplies ? { quickReplies: o.quickReplies } : {},
|
|
1016
1070
|
...o.accent ? { accent: o.accent } : {},
|
|
1017
|
-
...(
|
|
1018
|
-
i18n:
|
|
1071
|
+
...(te = o.user) != null && te.name || (oe = o.user) != null && oe.avatar ? { userInfo: { ...o.user.name ? { name: o.user.name } : {}, ...o.user.avatar ? { avatar: o.user.avatar } : {} } } : {},
|
|
1072
|
+
i18n: he
|
|
1019
1073
|
});
|
|
1020
1074
|
try {
|
|
1021
|
-
localStorage.getItem(
|
|
1075
|
+
localStorage.getItem(Q) && L.completePreChat();
|
|
1022
1076
|
} catch {
|
|
1023
1077
|
}
|
|
1024
|
-
const
|
|
1078
|
+
const Z = o.user && (o.user.name || o.user.email || o.user.avatar || o.user.meta) ? {
|
|
1025
1079
|
...o.user.name ? { name: o.user.name } : {},
|
|
1026
1080
|
...o.user.email ? { email: o.user.email } : {},
|
|
1027
1081
|
...o.user.avatar ? { avatar: o.user.avatar } : {},
|
|
1028
1082
|
...o.user.meta ? { meta: o.user.meta } : {}
|
|
1029
|
-
} : void 0,
|
|
1083
|
+
} : void 0, we = {
|
|
1030
1084
|
type: "open",
|
|
1031
1085
|
profileId: o.profileId,
|
|
1032
1086
|
// Direct conversations use the kind/peerId pair; the dm:… subject key is
|
|
1033
1087
|
// server-derived and owner-keyed, so passing it as subjectId from the
|
|
1034
1088
|
// NON-owner side would find-or-create a junk duplicate thread.
|
|
1035
1089
|
...o.kind === "direct" && o.peerId ? { kind: "direct", peerId: o.peerId } : o.subjectId ? { subjectId: o.subjectId } : {},
|
|
1036
|
-
...
|
|
1037
|
-
...
|
|
1090
|
+
...r ? { linkFrom: r } : {},
|
|
1091
|
+
...Z ? { userInfo: Z } : {},
|
|
1038
1092
|
...typeof location < "u" ? { pageUrl: location.href } : {},
|
|
1039
1093
|
...typeof document < "u" && document.title ? { pageTitle: document.title } : {},
|
|
1040
1094
|
// Pass subject display info so the server can persist it to the Subject record.
|
|
1041
1095
|
// This is how listingTitle and listingMeta get saved without a separate API call.
|
|
1042
|
-
...(
|
|
1043
|
-
...(
|
|
1096
|
+
...(ne = o.subject) != null && ne.title ? { subjectTitle: o.subject.title } : {},
|
|
1097
|
+
...(ie = o.subject) != null && ie.subtitle ? { subjectMeta: o.subject.subtitle } : {}
|
|
1044
1098
|
};
|
|
1045
|
-
|
|
1099
|
+
C = new Ce({
|
|
1046
1100
|
...o.refreshToken ? { refreshToken: o.refreshToken } : {},
|
|
1047
1101
|
url: f,
|
|
1048
1102
|
token: a,
|
|
1049
|
-
open:
|
|
1103
|
+
open: we,
|
|
1050
1104
|
getCursor: () => d.highestSeq(),
|
|
1051
|
-
onStatusChange: (n, p) =>
|
|
1105
|
+
onStatusChange: (n, p) => L.setConnStatus(n, p),
|
|
1052
1106
|
onFrame(n) {
|
|
1053
|
-
if (
|
|
1054
|
-
if (
|
|
1107
|
+
if (J.apply(n), n.type === "opened") {
|
|
1108
|
+
if (c = n.conversation.id, !u) {
|
|
1055
1109
|
u = !0;
|
|
1056
|
-
for (const p of
|
|
1057
|
-
|
|
1110
|
+
for (const p of y.load())
|
|
1111
|
+
C.send({ type: "send", conversationId: c, clientMsgId: p.clientMsgId, content: p.content });
|
|
1058
1112
|
}
|
|
1059
|
-
|
|
1113
|
+
ve(f, a, c, d, L, b), z.length && q(c);
|
|
1060
1114
|
}
|
|
1061
|
-
if (n.type === "ack" &&
|
|
1062
|
-
n.bundle && (
|
|
1063
|
-
const g = [...
|
|
1064
|
-
for (const
|
|
1065
|
-
|
|
1115
|
+
if (n.type === "ack" && y.remove(n.clientMsgId), n.type === "prekeyBundle") {
|
|
1116
|
+
n.bundle && (M = !0, j.x3dhSendTo(n.bundle).then((p) => {
|
|
1117
|
+
const g = [...x.splice(0), ...S.splice(0)];
|
|
1118
|
+
for (const P of g) le(P.clientMsgId, P.text, p);
|
|
1119
|
+
L.render(d);
|
|
1066
1120
|
}));
|
|
1067
1121
|
return;
|
|
1068
1122
|
}
|
|
1069
1123
|
if (n.type === "message" && d.e2e) {
|
|
1070
|
-
const p =
|
|
1071
|
-
if (p && !
|
|
1072
|
-
|
|
1073
|
-
await
|
|
1124
|
+
const p = Ie(n.message.content);
|
|
1125
|
+
if (p && !j.ready) {
|
|
1126
|
+
j.x3dhReceiveFrom(p.x3dhIK, p.x3dhEK, p.x3dhSPK).then(async () => {
|
|
1127
|
+
await j.openFrame(n), d.apply(n), L.render(d);
|
|
1074
1128
|
});
|
|
1075
1129
|
return;
|
|
1076
1130
|
}
|
|
1077
1131
|
}
|
|
1078
1132
|
if (n.type === "peerkey") {
|
|
1079
|
-
|
|
1080
|
-
|
|
1133
|
+
j.onPeerKey(n.key).then(() => {
|
|
1134
|
+
de(), L.render(d);
|
|
1081
1135
|
});
|
|
1082
1136
|
return;
|
|
1083
1137
|
}
|
|
1084
1138
|
(async () => {
|
|
1085
|
-
if (d.e2e && await
|
|
1086
|
-
|
|
1087
|
-
const p = await
|
|
1088
|
-
|
|
1089
|
-
const g = await
|
|
1090
|
-
|
|
1139
|
+
if (d.e2e && await j.openFrame(n), d.apply(n), n.type === "message" && n.message.senderId !== a && !n.message.internal && (A(), $()), d.e2e && c && !D) {
|
|
1140
|
+
D = !0;
|
|
1141
|
+
const p = await j.initX3DH();
|
|
1142
|
+
C.send({ type: "uploadPrekeys", ...p });
|
|
1143
|
+
const g = await j.begin();
|
|
1144
|
+
C.send({ type: "pubkey", conversationId: c, key: g });
|
|
1091
1145
|
}
|
|
1092
|
-
|
|
1146
|
+
L.render(d);
|
|
1093
1147
|
})();
|
|
1094
1148
|
}
|
|
1095
|
-
}),
|
|
1096
|
-
const
|
|
1097
|
-
s = !0, clearTimeout(i),
|
|
1149
|
+
}), C.connect(), L.render(d);
|
|
1150
|
+
const H = o.launcher ? ce(o) : null, _ = { close: () => {
|
|
1151
|
+
s = !0, clearTimeout(i), C.close(), w == null || w.remove(), L.destroy(), J.destroy(), l && T && l.removeEventListener("change", T), m && (document.removeEventListener("keydown", m), m = null), O.delete(o.el), H && W.get(H) === _ && W.delete(H);
|
|
1098
1152
|
} };
|
|
1099
|
-
return
|
|
1153
|
+
return O.set(o.el, _), H && W.set(H, _), _;
|
|
1100
1154
|
}
|
|
1101
1155
|
export {
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1156
|
+
ke as ChatStore,
|
|
1157
|
+
Ce as ConnectionManager,
|
|
1158
|
+
Te as E2ESession,
|
|
1159
|
+
ye as PersistentOutbox,
|
|
1160
|
+
Be as Renderer,
|
|
1161
|
+
Ke as asConversationId,
|
|
1162
|
+
Ie as extractX3DHInit,
|
|
1163
|
+
We as httpBaseFromWsUrl,
|
|
1164
|
+
_e as mount,
|
|
1165
|
+
me as resolveRelayUrls,
|
|
1166
|
+
ve as restoreHistory,
|
|
1167
|
+
Ne as unmount
|
|
1114
1168
|
};
|
|
1115
1169
|
//# sourceMappingURL=index.js.map
|