@mrrocket/sdk 0.13.0 → 0.14.0
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/CHANGELOG.md +8 -1
- package/README.md +34 -0
- package/dist/browser/mrrocket-flows.js +11 -2
- package/dist/browser/mrrocket-messenger.js +143 -65
- package/dist/browser/mrrocket.js +1 -1
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +2 -1
- package/dist/browser.js.map +1 -1
- package/dist/client.d.ts +12 -0
- package/dist/client.js +22 -0
- package/dist/client.js.map +1 -1
- package/dist/context.d.ts +3 -0
- package/dist/context.js.map +1 -1
- package/dist/core.d.ts +4 -1
- package/dist/core.js +1 -1
- package/dist/core.js.map +1 -1
- package/dist/flows-ui.d.ts +6 -4
- package/dist/flows-ui.js +99 -4
- package/dist/flows-ui.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/messenger-ui.d.ts +22 -0
- package/dist/messenger-ui.js +313 -79
- package/dist/messenger-ui.js.map +1 -1
- package/dist/paywall.d.ts +123 -0
- package/dist/paywall.js +131 -0
- package/dist/paywall.js.map +1 -0
- package/dist/react-native/index.d.cts +134 -3
- package/dist/react-native/index.d.ts +134 -3
- package/dist/react-native/index.js +204 -4
- package/dist/react-native/index.js.map +1 -1
- package/dist/styles-css.d.ts +1 -1
- package/dist/styles-css.js +141 -63
- package/dist/styles-css.js.map +1 -1
- package/package.json +1 -1
package/dist/messenger-ui.js
CHANGED
|
@@ -40,7 +40,7 @@ var el = (tag, attrs = {}, ...kids) => {
|
|
|
40
40
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
41
41
|
var icon = (d, size = 16) => {
|
|
42
42
|
const svg = document.createElementNS(SVG_NS, "svg");
|
|
43
|
-
for (const [k, v] of Object.entries({ class: "ckw-icon", width: String(size), height: String(size), viewBox: "0 0
|
|
43
|
+
for (const [k, v] of Object.entries({ class: "ckw-icon", width: String(size), height: String(size), viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "1.75", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }))
|
|
44
44
|
svg.setAttribute(k, v);
|
|
45
45
|
const path = document.createElementNS(SVG_NS, "path");
|
|
46
46
|
path.setAttribute("d", d);
|
|
@@ -48,16 +48,30 @@ var icon = (d, size = 16) => {
|
|
|
48
48
|
return svg;
|
|
49
49
|
};
|
|
50
50
|
var I = {
|
|
51
|
-
cross: "
|
|
52
|
-
chat: "
|
|
53
|
-
send: "
|
|
54
|
-
up: "
|
|
55
|
-
home: "
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
51
|
+
cross: "M18 6 6 18M6 6l12 12",
|
|
52
|
+
chat: "M7.9 20A9 9 0 1 0 4 16.1L2 22z",
|
|
53
|
+
send: "M5 12h14M12 5l7 7-7 7",
|
|
54
|
+
up: "M12 19V5M5 12l7-7 7 7",
|
|
55
|
+
home: "M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8M3 10a2 2 0 0 1 .709-1.528l7-6a2 2 0 0 1 2.582 0l7 6A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z",
|
|
56
|
+
back: "m15 18-6-6 6-6",
|
|
57
|
+
next: "m9 18 6-6-6-6",
|
|
58
|
+
search: "M19 11a8 8 0 1 1-16 0 8 8 0 0 1 16 0zM21 21l-4.3-4.3",
|
|
59
|
+
doc: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7zM14 2v4a2 2 0 0 0 2 2h4M10 9H8M16 13H8M16 17H8",
|
|
60
|
+
book: "M12 7v14M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z",
|
|
61
|
+
dots: "M13 12a1 1 0 1 1-2 0 1 1 0 0 1 2 0zM13 5a1 1 0 1 1-2 0 1 1 0 0 1 2 0zM13 19a1 1 0 1 1-2 0 1 1 0 0 1 2 0z",
|
|
62
|
+
expand: "M15 3h6v6M21 3l-7 7M3 21l7-7M9 21H3v-6",
|
|
63
|
+
collapse: "m14 10 7-7M20 10h-6V4M3 21l7-7M4 14h6v6",
|
|
64
|
+
minus: "M5 12h14"
|
|
65
|
+
};
|
|
66
|
+
var BUBBLE = "M7.9 20A9 9 0 1 0 4 16.1L2 22z";
|
|
67
|
+
var filled = (d, size) => {
|
|
68
|
+
const svg = document.createElementNS(SVG_NS, "svg");
|
|
69
|
+
for (const [k, v] of Object.entries({ class: "ckw-icon", width: String(size), height: String(size), viewBox: "0 0 24 24", fill: "currentColor", stroke: "currentColor", "stroke-width": "1.5", "stroke-linejoin": "round", "aria-hidden": "true" }))
|
|
70
|
+
svg.setAttribute(k, v);
|
|
71
|
+
const path = document.createElementNS(SVG_NS, "path");
|
|
72
|
+
path.setAttribute("d", d);
|
|
73
|
+
svg.appendChild(path);
|
|
74
|
+
return svg;
|
|
61
75
|
};
|
|
62
76
|
var chime = /* @__PURE__ */ (() => {
|
|
63
77
|
let ctx = null;
|
|
@@ -139,7 +153,7 @@ var mountMessenger = (o) => {
|
|
|
139
153
|
for (const fn of queued.splice(0)) fn(real);
|
|
140
154
|
};
|
|
141
155
|
const timer = setTimeout(() => start(null), LOOK_WAIT_MS);
|
|
142
|
-
createApi({ host: o.host, apiKey: o.apiKey, distinctId: o.distinctId(), user: o.user() }).messengerLook(ctrl.signal).then((look) => start(look)).catch(() => start(null)).finally(() => clearTimeout(timer));
|
|
156
|
+
(o.client ?? createApi({ host: o.host, apiKey: o.apiKey, distinctId: o.distinctId(), user: o.user() })).messengerLook(ctrl.signal).then((look) => start(look)).catch(() => start(null)).finally(() => clearTimeout(timer));
|
|
143
157
|
return {
|
|
144
158
|
open: (v) => later((h) => h.open(v)),
|
|
145
159
|
close: () => real?.close(),
|
|
@@ -165,13 +179,14 @@ var build = (o) => {
|
|
|
165
179
|
const helpOn = o.help ?? true;
|
|
166
180
|
const soundOn = o.sound ?? true;
|
|
167
181
|
const previewOn = o.preview ?? true;
|
|
168
|
-
const api = () => createApi({ host: o.host, apiKey: o.apiKey, distinctId: o.distinctId(), user: o.user() });
|
|
182
|
+
const api = () => o.client ?? createApi({ host: o.host, apiKey: o.apiKey, distinctId: o.distinctId(), user: o.user() });
|
|
169
183
|
const root = el("div", { class: "ckw-root", "data-theme": o.theme ?? "auto" });
|
|
184
|
+
if (o.container) root.setAttribute("data-contained", "");
|
|
170
185
|
if (o.accent) {
|
|
171
186
|
root.style.setProperty("--ckw-accent", o.accent);
|
|
172
187
|
root.style.setProperty("--ckw-accent-ink", inkOn(o.accent));
|
|
173
188
|
}
|
|
174
|
-
document.body.appendChild(root);
|
|
189
|
+
(o.container ?? document.body).appendChild(root);
|
|
175
190
|
let open = false;
|
|
176
191
|
let view = "home";
|
|
177
192
|
let thread = null;
|
|
@@ -187,6 +202,8 @@ var build = (o) => {
|
|
|
187
202
|
let query = "";
|
|
188
203
|
let rated = /* @__PURE__ */ new Set();
|
|
189
204
|
let hasArticles = null;
|
|
205
|
+
let collection = null;
|
|
206
|
+
let wide = false;
|
|
190
207
|
const teamMsgs = (t) => (t?.messages ?? []).filter((m) => m.from !== "visitor");
|
|
191
208
|
const lastTeamId = (t) => teamMsgs(t).at(-1)?.id ?? "";
|
|
192
209
|
const watching = () => open && view === "messages" && document.visibilityState !== "hidden";
|
|
@@ -217,23 +234,57 @@ var build = (o) => {
|
|
|
217
234
|
if (id) writeSeen(id);
|
|
218
235
|
};
|
|
219
236
|
const avatar = (size) => el("span", { class: `ckw-msgr-av${size ? " ckw-msgr-av-sm" : ""}`, "aria-hidden": "true" }, initial);
|
|
237
|
+
const leaving = /* @__PURE__ */ new Map();
|
|
238
|
+
const enter = (node, parent = root) => {
|
|
239
|
+
clearTimeout(leaving.get(node));
|
|
240
|
+
leaving.delete(node);
|
|
241
|
+
node.removeAttribute("data-out");
|
|
242
|
+
if (!node.isConnected) parent.appendChild(node);
|
|
243
|
+
};
|
|
244
|
+
const leave = (node, ms = 180) => {
|
|
245
|
+
if (!node.isConnected || leaving.has(node)) return;
|
|
246
|
+
node.setAttribute("data-out", "");
|
|
247
|
+
leaving.set(
|
|
248
|
+
node,
|
|
249
|
+
setTimeout(() => {
|
|
250
|
+
leaving.delete(node);
|
|
251
|
+
node.removeAttribute("data-out");
|
|
252
|
+
node.remove();
|
|
253
|
+
}, ms)
|
|
254
|
+
);
|
|
255
|
+
};
|
|
256
|
+
const replay = (node, cls) => {
|
|
257
|
+
node.classList.remove(cls);
|
|
258
|
+
void node.offsetWidth;
|
|
259
|
+
node.classList.add(cls);
|
|
260
|
+
};
|
|
220
261
|
const fab = el("button", { type: "button", class: `ckw-fab ckw-msgr-fab${label ? "" : " ckw-msgr-round"}`, "data-pos": position, "aria-haspopup": "dialog" });
|
|
262
|
+
const fabIcons = el(
|
|
263
|
+
"span",
|
|
264
|
+
{ class: "ckw-msgr-fab-ic", "aria-hidden": "true" },
|
|
265
|
+
el("span", { class: "ckw-msgr-fab-i", "data-i": "chat" }, filled(BUBBLE, label ? 20 : 28)),
|
|
266
|
+
el("span", { class: "ckw-msgr-fab-i", "data-i": "x" }, icon(I.cross, label ? 16 : 22))
|
|
267
|
+
);
|
|
268
|
+
const fabCount = el("span", { class: "ckw-msgr-count", "aria-hidden": "true" });
|
|
269
|
+
fab.append(fabIcons);
|
|
270
|
+
if (label) fab.append(el("span", {}, label));
|
|
221
271
|
const prev = el("div", { class: "ckw-msgr-preview", "data-pos": position, role: "status" });
|
|
222
|
-
let fabShows = null;
|
|
223
272
|
const drawFab = () => {
|
|
224
|
-
|
|
225
|
-
if (
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
273
|
+
fab.toggleAttribute("data-open", open);
|
|
274
|
+
if (unseen.length && !open) {
|
|
275
|
+
const n = String(Math.min(unseen.length, 9));
|
|
276
|
+
if (fabCount.textContent !== n) fabCount.textContent = n;
|
|
277
|
+
if (!fabCount.isConnected) fab.append(fabCount);
|
|
278
|
+
} else fabCount.remove();
|
|
230
279
|
fab.setAttribute("aria-expanded", String(open));
|
|
231
280
|
fab.setAttribute("aria-label", open ? "Close chat" : unseen.length ? `Open chat, ${unseen.length} new ${unseen.length === 1 ? "reply" : "replies"}` : "Open chat");
|
|
232
281
|
drawPreview();
|
|
233
282
|
};
|
|
283
|
+
const previewShown = () => previewOn && !open && !previewGone && !!unseen.length && launcherOn;
|
|
234
284
|
const drawPreview = () => {
|
|
235
285
|
const m = unseen.at(-1);
|
|
236
|
-
if (!
|
|
286
|
+
if (!previewShown() || !m) return leave(prev);
|
|
287
|
+
hideTeaser(true);
|
|
237
288
|
const x = el("button", { type: "button", class: "ckw-msgr-preview-x", "aria-label": "Dismiss" }, icon(I.cross, 12));
|
|
238
289
|
x.addEventListener("click", (e) => {
|
|
239
290
|
e.stopPropagation();
|
|
@@ -253,40 +304,163 @@ var build = (o) => {
|
|
|
253
304
|
);
|
|
254
305
|
card.addEventListener("click", () => show("messages"));
|
|
255
306
|
prev.replaceChildren(card, x);
|
|
256
|
-
|
|
307
|
+
enter(prev);
|
|
308
|
+
};
|
|
309
|
+
const teaser = el("div", { class: "ckw-msgr-teaser", "data-pos": position });
|
|
310
|
+
let teaserTimer;
|
|
311
|
+
const showTeaser = () => {
|
|
312
|
+
clearTimeout(teaserTimer);
|
|
313
|
+
if (open || previewShown() || !launcherOn) return;
|
|
314
|
+
const chat = el("button", { type: "button", class: "ckw-msgr-teaser-b", "data-main": "" }, icon(I.chat), el("span", {}, "Chat with us"));
|
|
315
|
+
chat.addEventListener("click", () => show("messages"));
|
|
316
|
+
const buttons = [chat];
|
|
317
|
+
if (helpOn && hasArticles) {
|
|
318
|
+
const search = el("button", { type: "button", class: "ckw-msgr-teaser-b" }, icon(I.search), el("span", {}, "Search"));
|
|
319
|
+
search.addEventListener("click", () => show("help"));
|
|
320
|
+
buttons.push(search);
|
|
321
|
+
}
|
|
322
|
+
teaser.replaceChildren(
|
|
323
|
+
el(
|
|
324
|
+
"div",
|
|
325
|
+
{ class: "ckw-msgr-teaser-top" },
|
|
326
|
+
el("span", { class: "ckw-msgr-teaser-t" }, el("b", {}, greeting), el("span", { class: "ckw-msgr-online" }, reply)),
|
|
327
|
+
avatar()
|
|
328
|
+
),
|
|
329
|
+
el("div", { class: "ckw-msgr-teaser-row" }, ...buttons)
|
|
330
|
+
);
|
|
331
|
+
enter(teaser);
|
|
257
332
|
};
|
|
333
|
+
function hideTeaser(now = false) {
|
|
334
|
+
clearTimeout(teaserTimer);
|
|
335
|
+
if (now) return leave(teaser, 140);
|
|
336
|
+
teaserTimer = setTimeout(() => leave(teaser, 140), 260);
|
|
337
|
+
}
|
|
338
|
+
const hoverable = (e) => e.pointerType === "mouse";
|
|
339
|
+
for (const node of [fab, teaser]) {
|
|
340
|
+
node.addEventListener("pointerenter", (e) => hoverable(e) && (node === fab ? showTeaser() : clearTimeout(teaserTimer)));
|
|
341
|
+
node.addEventListener("pointerleave", (e) => hoverable(e) && hideTeaser());
|
|
342
|
+
}
|
|
258
343
|
fab.addEventListener("click", () => {
|
|
259
344
|
chime.unlock();
|
|
345
|
+
hideTeaser(true);
|
|
260
346
|
if (open) close();
|
|
261
347
|
else show(unseen.length ? "messages" : "home");
|
|
262
348
|
});
|
|
263
349
|
if (launcherOn) root.appendChild(fab);
|
|
264
350
|
const pop = el("div", { class: "ckw-pop ckw-msgr", "data-pos": position, role: "dialog", "aria-label": title });
|
|
265
|
-
const
|
|
351
|
+
const bar = el("div", { class: "ckw-msgr-bar" });
|
|
266
352
|
const body = el("div", { class: "ckw-pop-body ckw-msgr-body" });
|
|
267
|
-
const tabs = el("nav", { class: "ckw-msgr-tabs", "aria-label": "Messenger" });
|
|
268
353
|
pop.addEventListener("click", () => chime.unlock());
|
|
354
|
+
const lead = el("span", { class: "ckw-msgr-lead" });
|
|
355
|
+
const seg = el("nav", { class: "ckw-msgr-seg", "aria-label": "Messenger" });
|
|
356
|
+
const mark = el("span", { class: "ckw-msgr-seg-mark", "aria-hidden": "true" });
|
|
357
|
+
const segTab = (v, name, d) => {
|
|
358
|
+
const b = el("button", { type: "button", class: "ckw-msgr-seg-b" }, icon(d, 15), el("span", {}, name));
|
|
359
|
+
b.addEventListener("click", () => {
|
|
360
|
+
collection = null;
|
|
361
|
+
go(v);
|
|
362
|
+
});
|
|
363
|
+
return b;
|
|
364
|
+
};
|
|
365
|
+
const chatTab = segTab("messages", "Chat", I.chat);
|
|
366
|
+
const helpTab = segTab("help", "Help", I.book);
|
|
367
|
+
const tabCount = el("span", { class: "ckw-msgr-count ckw-msgr-count-tab", "aria-hidden": "true" });
|
|
368
|
+
const menuBtn = el("button", { type: "button", class: "ckw-msgr-ib", "aria-label": "More", "aria-haspopup": "menu", "aria-expanded": "false" }, icon(I.dots, 18));
|
|
369
|
+
const xBtn = el("button", { type: "button", class: "ckw-msgr-ib ckw-msgr-x", "aria-label": "Close messenger" }, icon(I.cross));
|
|
370
|
+
xBtn.addEventListener("click", () => close());
|
|
371
|
+
bar.append(lead, seg, el("span", { class: "ckw-msgr-trail" }, menuBtn, xBtn));
|
|
372
|
+
const menu = el("div", { class: "ckw-msgr-menu", role: "menu" });
|
|
373
|
+
const menuOpen = () => menu.isConnected && !menu.hasAttribute("data-out");
|
|
374
|
+
const closeMenu = () => {
|
|
375
|
+
menuBtn.setAttribute("aria-expanded", "false");
|
|
376
|
+
leave(menu, 120);
|
|
377
|
+
};
|
|
378
|
+
const menuItem = (d, name, act) => {
|
|
379
|
+
const b = el("button", { type: "button", class: "ckw-msgr-menu-i", role: "menuitem" }, icon(d, 15), el("span", {}, name));
|
|
380
|
+
b.addEventListener("click", (e) => {
|
|
381
|
+
e.stopPropagation();
|
|
382
|
+
closeMenu();
|
|
383
|
+
act();
|
|
384
|
+
});
|
|
385
|
+
return b;
|
|
386
|
+
};
|
|
387
|
+
menuBtn.addEventListener("click", (e) => {
|
|
388
|
+
e.stopPropagation();
|
|
389
|
+
if (menuOpen()) return closeMenu();
|
|
390
|
+
menu.replaceChildren(
|
|
391
|
+
el("span", { class: "ckw-msgr-menu-h" }, "Quick actions"),
|
|
392
|
+
menuItem(I.minus, "Minimize chat", () => close()),
|
|
393
|
+
menuItem(wide ? I.collapse : I.expand, wide ? "Collapse view" : "Expand view", () => {
|
|
394
|
+
wide = !wide;
|
|
395
|
+
pop.toggleAttribute("data-wide", wide);
|
|
396
|
+
requestAnimationFrame(placeMark);
|
|
397
|
+
})
|
|
398
|
+
);
|
|
399
|
+
menuBtn.setAttribute("aria-expanded", "true");
|
|
400
|
+
enter(menu, pop);
|
|
401
|
+
menu.querySelector("button")?.focus();
|
|
402
|
+
});
|
|
403
|
+
pop.addEventListener("click", () => menuOpen() && closeMenu());
|
|
404
|
+
function placeMark() {
|
|
405
|
+
const current = view === "messages" ? chatTab : view !== "home" ? helpTab : null;
|
|
406
|
+
if (!current || !current.isConnected) return mark.removeAttribute("data-on");
|
|
407
|
+
const first = !mark.hasAttribute("data-on");
|
|
408
|
+
if (first) mark.setAttribute("data-still", "");
|
|
409
|
+
mark.style.width = `${current.offsetWidth}px`;
|
|
410
|
+
mark.style.transform = `translateX(${current.offsetLeft}px)`;
|
|
411
|
+
mark.setAttribute("data-on", "");
|
|
412
|
+
if (first) requestAnimationFrame(() => mark.removeAttribute("data-still"));
|
|
413
|
+
}
|
|
414
|
+
const drawBar = () => {
|
|
415
|
+
const back = (to, name) => {
|
|
416
|
+
const b = el("button", { type: "button", class: "ckw-msgr-ib", "aria-label": name }, icon(I.back, 18));
|
|
417
|
+
b.addEventListener("click", to);
|
|
418
|
+
return b;
|
|
419
|
+
};
|
|
420
|
+
if (typeof view !== "string")
|
|
421
|
+
lead.replaceChildren(
|
|
422
|
+
back(() => go("help"), "Back to help")
|
|
423
|
+
);
|
|
424
|
+
else if (view === "help" && collection && !query.trim())
|
|
425
|
+
lead.replaceChildren(
|
|
426
|
+
back(() => {
|
|
427
|
+
collection = null;
|
|
428
|
+
go("help");
|
|
429
|
+
}, "All collections")
|
|
430
|
+
);
|
|
431
|
+
else {
|
|
432
|
+
const home = el("button", { type: "button", class: "ckw-msgr-ib", "aria-label": "Home", "aria-current": view === "home" ? "page" : "false" }, icon(I.home, 17));
|
|
433
|
+
home.addEventListener("click", () => go("home"));
|
|
434
|
+
lead.replaceChildren(home);
|
|
435
|
+
}
|
|
436
|
+
const tabsWanted = helpOn && hasArticles !== false ? [mark, chatTab, helpTab] : [mark, chatTab];
|
|
437
|
+
if (seg.childNodes.length !== tabsWanted.length) seg.replaceChildren(...tabsWanted);
|
|
438
|
+
chatTab.setAttribute("aria-current", view === "messages" ? "page" : "false");
|
|
439
|
+
helpTab.setAttribute("aria-current", view !== "home" && view !== "messages" ? "page" : "false");
|
|
440
|
+
if (unseen.length && view !== "messages") {
|
|
441
|
+
tabCount.textContent = String(Math.min(unseen.length, 9));
|
|
442
|
+
if (!tabCount.isConnected) chatTab.append(tabCount);
|
|
443
|
+
} else tabCount.remove();
|
|
444
|
+
};
|
|
269
445
|
const form = el("form", { class: "ckw-msgr-compose" });
|
|
270
446
|
const err = el("p", { class: "ckw-msgr-error", role: "alert" });
|
|
271
447
|
const email = el("input", { class: "ckw-input", type: "email", inputmode: "email", autocomplete: "email", placeholder: "Your email (optional), so we can follow up", "aria-label": "Your email (optional)", maxlength: "200" });
|
|
272
|
-
const row = el("div", { class: "ckw-msgr-
|
|
273
|
-
const text = el("textarea", { class: "ckw-textarea ckw-msgr-input", rows: "1", placeholder: "Write
|
|
448
|
+
const row = el("div", { class: "ckw-msgr-box" });
|
|
449
|
+
const text = el("textarea", { class: "ckw-textarea ckw-msgr-input", rows: "1", placeholder: "Write your message\u2026", "aria-label": "Message", maxlength: "4000" });
|
|
274
450
|
const send = el("button", { type: "submit", class: "ckw-msgr-send", "aria-label": "Send" }, icon(I.up));
|
|
275
|
-
row.append(text, send);
|
|
451
|
+
row.append(text, el("div", { class: "ckw-msgr-box-foot" }, el("span", { class: "ckw-msgr-hint" }, "Enter to send"), send));
|
|
452
|
+
row.addEventListener("click", (e) => e.target === row && text.focus());
|
|
276
453
|
form.append(row);
|
|
277
454
|
const list = el("ol", { class: "ckw-msgs", "aria-live": "polite", "aria-label": "Messages" });
|
|
278
455
|
const needEmail = () => askEmail && !o.user()?.email && !thread?.hasEmail;
|
|
279
456
|
const emailOk = () => !email.value.trim() || EMAIL.test(email.value.trim());
|
|
280
457
|
const canSend = () => !!text.value.trim() && !pending && emailOk();
|
|
281
|
-
const closeBtn = () => {
|
|
282
|
-
const b = el("button", { type: "button", class: "ckw-btn ckw-btn-ghost ckw-msgr-x", "aria-label": "Close messenger" }, icon(I.cross));
|
|
283
|
-
b.addEventListener("click", () => close());
|
|
284
|
-
return b;
|
|
285
|
-
};
|
|
286
458
|
const go = (v) => {
|
|
459
|
+
const changed = JSON.stringify(v) !== JSON.stringify(view);
|
|
287
460
|
view = v;
|
|
288
461
|
drawn = -1;
|
|
289
462
|
draw();
|
|
463
|
+
if (changed) replay(body, "ckw-msgr-enter");
|
|
290
464
|
if (v === "messages") {
|
|
291
465
|
markSeen();
|
|
292
466
|
drawFab();
|
|
@@ -310,9 +484,19 @@ var build = (o) => {
|
|
|
310
484
|
b.addEventListener("click", () => go({ article: a.id }));
|
|
311
485
|
return b;
|
|
312
486
|
};
|
|
313
|
-
const
|
|
487
|
+
const helpRow = (name, sub, meta, act) => {
|
|
488
|
+
const b = el(
|
|
489
|
+
"button",
|
|
490
|
+
{ type: "button", class: "ckw-msgr-hrow" },
|
|
491
|
+
el("span", { class: "ckw-msgr-hrow-main" }, el("b", {}, name), sub ? el("span", { class: "ckw-msgr-hrow-sub" }, sub) : null, meta ? el("span", { class: "ckw-msgr-hrow-meta" }, meta) : null),
|
|
492
|
+
icon(I.next, 16)
|
|
493
|
+
);
|
|
494
|
+
b.addEventListener("click", act);
|
|
495
|
+
return b;
|
|
496
|
+
};
|
|
497
|
+
const searchBox = (placeholder = "Search for help") => {
|
|
314
498
|
const wrap = el("label", { class: "ckw-msgr-search" });
|
|
315
|
-
const input = el("input", { class: "ckw-msgr-search-in", type: "search", placeholder
|
|
499
|
+
const input = el("input", { class: "ckw-msgr-search-in", type: "search", placeholder, "aria-label": "Search for help", maxlength: "200" });
|
|
316
500
|
input.value = query;
|
|
317
501
|
let t;
|
|
318
502
|
input.addEventListener("input", () => {
|
|
@@ -329,10 +513,10 @@ var build = (o) => {
|
|
|
329
513
|
if (view !== "help") go("help");
|
|
330
514
|
}
|
|
331
515
|
});
|
|
332
|
-
wrap.append(
|
|
516
|
+
wrap.append(icon(I.search, 16), input);
|
|
333
517
|
return wrap;
|
|
334
518
|
};
|
|
335
|
-
const helpSearch = searchBox();
|
|
519
|
+
const helpSearch = searchBox("Search our help center\u2026");
|
|
336
520
|
const helpInput = helpSearch.querySelector("input");
|
|
337
521
|
let loadingArticles = false;
|
|
338
522
|
const loadArticles = async (force = false) => {
|
|
@@ -352,8 +536,13 @@ var build = (o) => {
|
|
|
352
536
|
draw();
|
|
353
537
|
};
|
|
354
538
|
const drawHome = () => {
|
|
355
|
-
|
|
356
|
-
|
|
539
|
+
const hero = el(
|
|
540
|
+
"div",
|
|
541
|
+
{ class: "ckw-msgr-hero" },
|
|
542
|
+
el("span", { class: "ckw-msgr-brand" }, avatar("sm"), el("span", {}, title)),
|
|
543
|
+
el("p", { class: "ckw-msgr-hello" }, greeting),
|
|
544
|
+
el("span", { class: "ckw-msgr-online" }, reply)
|
|
545
|
+
);
|
|
357
546
|
const last = (thread?.messages ?? []).at(-1);
|
|
358
547
|
const parts = [hero];
|
|
359
548
|
if (last) {
|
|
@@ -395,30 +584,50 @@ var build = (o) => {
|
|
|
395
584
|
body.replaceChildren(...parts);
|
|
396
585
|
};
|
|
397
586
|
const drawHelp = () => {
|
|
398
|
-
head.replaceChildren(el("span", {}, "Help"), closeBtn());
|
|
399
587
|
if (helpInput.value !== query) helpInput.value = query;
|
|
400
|
-
const
|
|
588
|
+
const q = query.trim();
|
|
589
|
+
const all = articles ?? [];
|
|
590
|
+
const groups = /* @__PURE__ */ new Map();
|
|
591
|
+
for (const a of all) groups.set(a.collection, [...groups.get(a.collection) ?? [], a]);
|
|
592
|
+
const inside = !q && collection !== null ? groups.get(collection) ?? [] : null;
|
|
593
|
+
const heading = q ? "Search results" : inside ? collection ?? "" : "Most read articles";
|
|
594
|
+
const parts = [el("h2", { class: "ckw-msgr-help-h" }, heading), helpSearch];
|
|
401
595
|
if (articles === null) parts.push(el("div", { class: "ckw-skel" }));
|
|
402
|
-
else if (!
|
|
596
|
+
else if (!all.length) {
|
|
403
597
|
const ask = el("button", { type: "button", class: "ckw-btn ckw-btn-primary" }, "Send us a message");
|
|
404
598
|
ask.addEventListener("click", () => go("messages"));
|
|
405
|
-
parts.push(el("div", { class: "ckw-msgr-empty" }, el("p", {},
|
|
406
|
-
} else if (
|
|
599
|
+
parts.push(el("div", { class: "ckw-msgr-empty" }, el("p", {}, q ? `Nothing found for \u201C${q}\u201D.` : "No help articles yet."), ask));
|
|
600
|
+
} else if (q || inside)
|
|
601
|
+
parts.push(
|
|
602
|
+
el(
|
|
603
|
+
"div",
|
|
604
|
+
{ class: "ckw-msgr-hlist" },
|
|
605
|
+
...(inside ?? all).map((a) => helpRow(a.title, a.excerpt.startsWith(a.title) ? a.excerpt.slice(a.title.length).trim() : a.excerpt, q ? a.collection : "", () => go({ article: a.id })))
|
|
606
|
+
)
|
|
607
|
+
);
|
|
608
|
+
else
|
|
609
|
+
parts.push(
|
|
610
|
+
el(
|
|
611
|
+
"div",
|
|
612
|
+
{ class: "ckw-msgr-hlist" },
|
|
613
|
+
...[...groups].map(
|
|
614
|
+
([name, items]) => helpRow(name, items.map((a) => a.title).join(", "), `${items.length} ${items.length === 1 ? "article" : "articles"}`, () => {
|
|
615
|
+
collection = name;
|
|
616
|
+
go("help");
|
|
617
|
+
replay(body, "ckw-msgr-enter");
|
|
618
|
+
})
|
|
619
|
+
)
|
|
620
|
+
)
|
|
621
|
+
);
|
|
622
|
+
if (body.childNodes[1] !== helpSearch) body.replaceChildren(...parts);
|
|
407
623
|
else {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
parts.push(el("section", { class: "ckw-msgr-group" }, el("h3", { class: "ckw-msgr-group-h" }, `${name} \xB7 ${items.length}`), el("div", { class: "ckw-msgr-card ckw-msgr-card-col" }, ...items.map(articleRow))));
|
|
624
|
+
body.firstChild.replaceWith(parts[0]);
|
|
625
|
+
while (body.childNodes.length > 2) body.lastChild.remove();
|
|
626
|
+
body.append(...parts.slice(2));
|
|
412
627
|
}
|
|
413
|
-
if (body.firstChild !== helpSearch) body.replaceChildren(helpSearch);
|
|
414
|
-
while (body.childNodes.length > 1) body.lastChild.remove();
|
|
415
|
-
body.append(...parts.slice(1));
|
|
416
628
|
};
|
|
417
629
|
let articleShown = null;
|
|
418
630
|
const drawArticle = (id) => {
|
|
419
|
-
const back = el("button", { type: "button", class: "ckw-btn ckw-btn-ghost ckw-msgr-x", "aria-label": "Back to help" }, icon(I.back));
|
|
420
|
-
back.addEventListener("click", () => go("help"));
|
|
421
|
-
head.replaceChildren(back, el("span", { class: "ckw-msgr-head-t" }, "Help"), closeBtn());
|
|
422
631
|
if (articleShown?.id === id) return body.replaceChildren(articleShown.node);
|
|
423
632
|
const node = el("article", { class: "ckw-msgr-doc" }, el("div", { class: "ckw-skel" }));
|
|
424
633
|
articleShown = { id, node };
|
|
@@ -457,22 +666,42 @@ var build = (o) => {
|
|
|
457
666
|
};
|
|
458
667
|
let drawn = -1;
|
|
459
668
|
let listSig = "";
|
|
669
|
+
let listCount = -1;
|
|
670
|
+
const intro = () => el(
|
|
671
|
+
"div",
|
|
672
|
+
{ class: "ckw-msgr-intro" },
|
|
673
|
+
el("span", { class: "ckw-msgr-intro-av" }, avatar()),
|
|
674
|
+
el("span", { class: "ckw-msgr-intro-t" }, el("b", {}, title), el("span", { class: "ckw-msgr-online" }, reply))
|
|
675
|
+
);
|
|
676
|
+
const introNode = intro();
|
|
677
|
+
const suggestions = el("div", { class: "ckw-msgr-sugg" });
|
|
460
678
|
const drawMessages = () => {
|
|
461
|
-
head.replaceChildren(
|
|
462
|
-
el("span", { class: "ckw-msgr-who" }, avatar(), el("span", { class: "ckw-msgr-who-t" }, el("b", {}, title), el("span", {}, reply))),
|
|
463
|
-
closeBtn()
|
|
464
|
-
);
|
|
465
679
|
const msgs = thread?.messages ?? [];
|
|
466
|
-
const parts = [];
|
|
680
|
+
const parts = [introNode];
|
|
467
681
|
if (!loaded) parts.push(el("div", { class: "ckw-skel" }));
|
|
468
682
|
else {
|
|
469
683
|
const sig = `${msgs.map((m) => m.id).join(",")}|${pending ? pending.body : ""}|${Math.floor(Date.now() / 6e4)}`;
|
|
470
684
|
if (sig !== listSig) {
|
|
471
685
|
listSig = sig;
|
|
472
686
|
const greet = el("li", { class: "ckw-msg", "data-from": "them" }, el("div", { class: "ckw-bubble" }, greeting));
|
|
473
|
-
|
|
687
|
+
const items = [greet, ...msgs.map((m) => bubble(m)), ...pending ? [bubble(pending, true)] : []];
|
|
688
|
+
if (listCount >= 0) items.slice(listCount).forEach((li) => li.setAttribute("data-new", ""));
|
|
689
|
+
listCount = items.length;
|
|
690
|
+
list.replaceChildren(...items);
|
|
474
691
|
}
|
|
475
692
|
parts.push(list);
|
|
693
|
+
const top = !msgs.some((m) => m.from === "visitor") && !pending ? (articles ?? []).slice(0, 3) : [];
|
|
694
|
+
if (top.length) {
|
|
695
|
+
if (suggestions.childNodes.length !== top.length)
|
|
696
|
+
suggestions.replaceChildren(
|
|
697
|
+
...top.map((a) => {
|
|
698
|
+
const b = el("button", { type: "button", class: "ckw-msgr-sugg-b" }, a.title);
|
|
699
|
+
b.addEventListener("click", () => go({ article: a.id }));
|
|
700
|
+
return b;
|
|
701
|
+
})
|
|
702
|
+
);
|
|
703
|
+
parts.push(suggestions);
|
|
704
|
+
}
|
|
476
705
|
}
|
|
477
706
|
if (thread?.conversation?.status === "solved" && !pending) parts.push(el("p", { class: "ckw-fine ckw-msgr-note" }, "This conversation is closed. Write to start a new one."));
|
|
478
707
|
if (body.childNodes.length !== parts.length || parts.some((x, i) => body.childNodes[i] !== x)) body.replaceChildren(...parts);
|
|
@@ -491,28 +720,19 @@ var build = (o) => {
|
|
|
491
720
|
} else email.remove();
|
|
492
721
|
send.disabled = !canSend();
|
|
493
722
|
};
|
|
494
|
-
const drawTabs = () => {
|
|
495
|
-
const current = typeof view === "string" ? view : "help";
|
|
496
|
-
const tab = (v, name, d, badge = 0) => {
|
|
497
|
-
const b = el("button", { type: "button", class: "ckw-msgr-tab", "aria-current": current === v ? "page" : "false" }, icon(d, 18), el("span", {}, name));
|
|
498
|
-
if (badge) b.append(el("span", { class: "ckw-msgr-count ckw-msgr-count-tab" }, String(Math.min(badge, 9))));
|
|
499
|
-
b.addEventListener("click", () => go(v));
|
|
500
|
-
return b;
|
|
501
|
-
};
|
|
502
|
-
tabs.replaceChildren(tab("home", "Home", I.home), tab("messages", "Messages", I.chat, view === "messages" ? 0 : unseen.length), ...helpOn && hasArticles !== false ? [tab("help", "Help", I.help)] : []);
|
|
503
|
-
};
|
|
504
723
|
const draw = () => {
|
|
505
724
|
if (!open) return;
|
|
506
725
|
pop.dataset.view = typeof view === "string" ? view : "article";
|
|
726
|
+
drawBar();
|
|
507
727
|
if (view === "home") drawHome();
|
|
508
728
|
else if (view === "messages") drawMessages();
|
|
509
729
|
else if (view === "help") drawHelp();
|
|
510
730
|
else drawArticle(view.article);
|
|
511
|
-
const kids = [
|
|
731
|
+
const kids = [bar, body];
|
|
512
732
|
if (view === "messages") kids.push(form);
|
|
513
|
-
kids.push(
|
|
514
|
-
drawTabs();
|
|
733
|
+
if (menu.isConnected) kids.push(menu);
|
|
515
734
|
if (pop.childNodes.length !== kids.length || kids.some((k, i) => pop.childNodes[i] !== k)) pop.replaceChildren(...kids);
|
|
735
|
+
placeMark();
|
|
516
736
|
};
|
|
517
737
|
const tick = async () => {
|
|
518
738
|
ctrl?.abort();
|
|
@@ -537,10 +757,11 @@ var build = (o) => {
|
|
|
537
757
|
const ms = now ?? (watching() ? POLL_OPEN_MS : waiting && recent ? POLL_WAITING_MS : open || waiting ? POLL_IDLE_MS : 0);
|
|
538
758
|
if (ms || now === 0) poll = setTimeout(() => void tick(), ms);
|
|
539
759
|
}
|
|
540
|
-
|
|
760
|
+
const onVisible = () => {
|
|
541
761
|
if (document.visibilityState === "visible") schedule(0);
|
|
542
762
|
else clearTimeout(poll);
|
|
543
|
-
}
|
|
763
|
+
};
|
|
764
|
+
document.addEventListener("visibilitychange", onVisible);
|
|
544
765
|
const submit = async () => {
|
|
545
766
|
const msg = text.value.trim();
|
|
546
767
|
if (!msg || pending || !emailOk()) return;
|
|
@@ -571,12 +792,16 @@ var build = (o) => {
|
|
|
571
792
|
});
|
|
572
793
|
text.addEventListener("input", () => send.disabled = !canSend());
|
|
573
794
|
email.addEventListener("input", () => draw());
|
|
574
|
-
function show(v = "home") {
|
|
795
|
+
function show(v = "home", still = false) {
|
|
796
|
+
const was = open;
|
|
575
797
|
open = true;
|
|
576
798
|
view = v === "help" && !helpOn ? "home" : v;
|
|
577
799
|
drawn = -1;
|
|
578
800
|
previewGone = true;
|
|
579
|
-
|
|
801
|
+
hideTeaser(true);
|
|
802
|
+
pop.toggleAttribute("data-still", still);
|
|
803
|
+
enter(pop);
|
|
804
|
+
if (was) replay(body, "ckw-msgr-enter");
|
|
580
805
|
if (articles === null || view === "help" && query) void loadArticles();
|
|
581
806
|
draw();
|
|
582
807
|
drawFab();
|
|
@@ -589,26 +814,35 @@ var build = (o) => {
|
|
|
589
814
|
function close() {
|
|
590
815
|
if (!open) return;
|
|
591
816
|
open = false;
|
|
592
|
-
|
|
817
|
+
if (menu.isConnected) closeMenu();
|
|
818
|
+
leave(pop, 200);
|
|
593
819
|
drawFab();
|
|
594
820
|
schedule();
|
|
595
821
|
if (launcherOn) fab.focus();
|
|
596
822
|
}
|
|
597
823
|
const onKey = (e) => {
|
|
598
|
-
if (e.key
|
|
824
|
+
if (e.key !== "Escape" || !open) return;
|
|
825
|
+
if (menuOpen()) {
|
|
826
|
+
closeMenu();
|
|
827
|
+
menuBtn.focus();
|
|
828
|
+
} else close();
|
|
599
829
|
};
|
|
600
830
|
document.addEventListener("keydown", onKey);
|
|
601
831
|
void tick();
|
|
602
832
|
if (helpOn) void loadArticles();
|
|
603
833
|
drawFab();
|
|
834
|
+
if (o.opened) show(o.opened, true);
|
|
604
835
|
return {
|
|
605
836
|
open: (v) => show(v ?? "home"),
|
|
606
837
|
close,
|
|
607
838
|
toggle: () => open ? close() : show(),
|
|
608
839
|
destroy: () => {
|
|
609
840
|
clearTimeout(poll);
|
|
841
|
+
clearTimeout(teaserTimer);
|
|
842
|
+
for (const t of leaving.values()) clearTimeout(t);
|
|
610
843
|
ctrl?.abort();
|
|
611
844
|
document.removeEventListener("keydown", onKey);
|
|
845
|
+
document.removeEventListener("visibilitychange", onVisible);
|
|
612
846
|
root.remove();
|
|
613
847
|
}
|
|
614
848
|
};
|