@mrrocket/sdk 0.16.0 → 0.17.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.
@@ -15,7 +15,6 @@ var POLL_IDLE_MS = 3e4;
15
15
  var WAITING_FOR_MS = 10 * 6e4;
16
16
  var EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/;
17
17
  var SEEN_KEY = "ckw_msgr_seen";
18
- var whoLabel = { visitor: "You", team: "Team", ai: "AI agent", auto: "Team" };
19
18
  var readSeen = () => {
20
19
  try {
21
20
  return window.localStorage.getItem(SEEN_KEY) ?? "";
@@ -167,20 +166,52 @@ var blockOf = (b) => {
167
166
  }
168
167
  };
169
168
  var LOOK_WAIT_MS = 2500;
169
+ var LOOK_KEY = "ckw_msgr_look:";
170
+ var readCachedLook = (apiKey) => {
171
+ try {
172
+ const raw = window.localStorage.getItem(LOOK_KEY + apiKey);
173
+ return raw ? JSON.parse(raw) : null;
174
+ } catch {
175
+ return null;
176
+ }
177
+ };
178
+ var writeCachedLook = (apiKey, look) => {
179
+ try {
180
+ window.localStorage.setItem(LOOK_KEY + apiKey, JSON.stringify(look));
181
+ } catch {
182
+ }
183
+ };
170
184
  var mountMessenger = (o) => {
171
185
  let real = null;
186
+ let shown = "";
172
187
  let gone = false;
173
188
  const queued = [];
174
189
  const later = (fn) => real ? fn(real) : queued.push(fn);
175
190
  const ctrl = new AbortController();
191
+ const caching = !o.client && !!o.apiKey;
176
192
  const start = (look) => {
177
- if (real || gone) return;
193
+ if (gone) return;
194
+ const key = JSON.stringify(look ?? {});
195
+ if (real && key === shown) return;
196
+ if (real?.isOpen()) {
197
+ real.onClose(() => start(look));
198
+ return;
199
+ }
200
+ real?.destroy();
201
+ shown = key;
178
202
  const defined = Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
179
203
  real = build({ ...look ?? {}, ...defined, accent: o.accent ?? look?.accent, theme: o.theme ?? look?.theme, branding: look?.branding ?? true });
180
204
  for (const fn of queued.splice(0)) fn(real);
181
205
  };
182
- const timer = setTimeout(() => start(null), LOOK_WAIT_MS);
183
- (o.client ?? createApi({ host: o.host, apiKey: o.apiKey, distinctId: o.distinctId(), user: o.user(), userHash: o.userHash?.() })).messengerLook(ctrl.signal).then((look) => start(look)).catch(() => start(null)).finally(() => clearTimeout(timer));
206
+ const cached = caching ? readCachedLook(o.apiKey) : null;
207
+ if (cached) start(cached);
208
+ const timer = cached ? void 0 : setTimeout(() => start(null), LOOK_WAIT_MS);
209
+ (o.client ?? createApi({ host: o.host, apiKey: o.apiKey, distinctId: o.distinctId(), user: o.user(), userHash: o.userHash?.() })).messengerLook(ctrl.signal).then((look) => {
210
+ if (caching && look) writeCachedLook(o.apiKey, look);
211
+ start(look);
212
+ }).catch(() => {
213
+ if (!real) start(null);
214
+ }).finally(() => clearTimeout(timer));
184
215
  return {
185
216
  open: (v) => later((h) => h.open(v)),
186
217
  close: () => real?.close(),
@@ -203,6 +234,7 @@ var build = (o) => {
203
234
  const label = o.label ?? "";
204
235
  const reply = replyLine(o.replyTime);
205
236
  const initial = (title.trim()[0] ?? "?").toUpperCase();
237
+ const whoLabel = { visitor: "You", team: "Team", ai: o.agentName?.trim() || "AI agent", auto: "Team" };
206
238
  const launcherOn = o.launcher ?? true;
207
239
  const helpOn = o.help ?? true;
208
240
  const soundOn = o.sound ?? true;
@@ -223,6 +255,7 @@ var build = (o) => {
223
255
  o.glow?.slice(0, 2).forEach((c, i) => /^#[0-9a-f]{6}$/i.test(c) && root.style.setProperty(`--ckw-glow${i + 2}`, c));
224
256
  (o.container ?? document.body).appendChild(root);
225
257
  let open = false;
258
+ let afterClose = null;
226
259
  let view = "home";
227
260
  let thread = null;
228
261
  let loaded = false;
@@ -268,13 +301,22 @@ var build = (o) => {
268
301
  const id = lastTeamId(thread);
269
302
  if (id) writeSeen(id);
270
303
  };
271
- const avatar = (size) => el("span", { class: `ckw-msgr-av${size ? " ckw-msgr-av-sm" : ""}`, "aria-hidden": "true" }, initial);
304
+ const letter = (size) => el("span", { class: `ckw-msgr-av${size ? " ckw-msgr-av-sm" : ""}`, "aria-hidden": "true" }, initial);
305
+ const avatar = (size) => {
306
+ if (!o.icon) return letter(size);
307
+ const av = el("span", { class: `ckw-msgr-av ckw-msgr-av-img${size ? " ckw-msgr-av-sm" : ""}`, "aria-hidden": "true" });
308
+ const img = el("img", { src: o.icon, alt: "" });
309
+ img.addEventListener("error", () => av.replaceWith(letter(size)));
310
+ av.append(img);
311
+ return av;
312
+ };
272
313
  const logo = el("span", { class: "ckw-msgr-logo", "aria-hidden": "true" });
273
314
  if (o.logo) {
274
315
  const img = el("img", { src: o.logo, alt: "" });
275
316
  img.addEventListener("error", () => logo.replaceChildren(avatar("sm")));
276
317
  logo.append(img);
277
318
  } else logo.append(avatar("sm"));
319
+ const agentFace = () => o.agentPhoto ? el("img", { class: "ckw-msg-face", src: o.agentPhoto, alt: "" }) : null;
278
320
  const sky = el("div", { class: "ckw-msgr-sky", "aria-hidden": "true" });
279
321
  const leaving = /* @__PURE__ */ new Map();
280
322
  const enter = (node, parent = root) => {
@@ -326,7 +368,6 @@ var build = (o) => {
326
368
  const drawPreview = () => {
327
369
  const m = unseen.at(-1);
328
370
  if (!previewShown() || !m) return leave(prev);
329
- hideTeaser(true);
330
371
  const x = el("button", { type: "button", class: "ckw-msgr-preview-x", "aria-label": "Dismiss" }, icon(I.cross, 14));
331
372
  x.addEventListener("click", (e) => {
332
373
  e.stopPropagation();
@@ -347,43 +388,8 @@ var build = (o) => {
347
388
  prev.replaceChildren(card, x);
348
389
  enter(prev);
349
390
  };
350
- const teaser = el("div", { class: "ckw-msgr-teaser", "data-pos": position });
351
- let teaserTimer;
352
- const showTeaser = () => {
353
- clearTimeout(teaserTimer);
354
- if (open || previewShown() || !launcherOn) return;
355
- const chat = el("button", { type: "button", class: "ckw-msgr-teaser-b", "data-main": "" }, icon(I.chat), el("span", {}, "Chat"));
356
- chat.addEventListener("click", () => show("messages"));
357
- const buttons = [chat];
358
- if (helpOn && hasArticles) {
359
- const search = el("button", { type: "button", class: "ckw-msgr-teaser-b" }, icon(I.search), el("span", {}, "Search"));
360
- search.addEventListener("click", () => show("help"));
361
- buttons.push(search);
362
- }
363
- teaser.replaceChildren(
364
- el(
365
- "div",
366
- { class: "ckw-msgr-teaser-top" },
367
- el("span", { class: "ckw-msgr-teaser-t" }, el("b", {}, greeting), el("span", { class: "ckw-msgr-online" }, reply)),
368
- avatar()
369
- ),
370
- el("div", { class: "ckw-msgr-teaser-row" }, ...buttons)
371
- );
372
- enter(teaser);
373
- };
374
- function hideTeaser(now = false) {
375
- clearTimeout(teaserTimer);
376
- if (now) return leave(teaser, 140);
377
- teaserTimer = setTimeout(() => leave(teaser, 140), 260);
378
- }
379
- const hoverable = (e) => e.pointerType === "mouse";
380
- for (const node of [fab, teaser]) {
381
- node.addEventListener("pointerenter", (e) => hoverable(e) && (node === fab ? showTeaser() : clearTimeout(teaserTimer)));
382
- node.addEventListener("pointerleave", (e) => hoverable(e) && hideTeaser());
383
- }
384
391
  fab.addEventListener("click", () => {
385
392
  chime.unlock();
386
- hideTeaser(true);
387
393
  if (open) close();
388
394
  else show(unseen.length ? "messages" : "home");
389
395
  });
@@ -477,7 +483,7 @@ var build = (o) => {
477
483
  };
478
484
  const form = el("form", { class: "ckw-msgr-compose" });
479
485
  const err = el("p", { class: "ckw-msgr-error", role: "alert" });
480
- 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" });
486
+ const email = el("input", { class: "ckw-input ckw-msgr-email", type: "email", inputmode: "email", autocomplete: "email", placeholder: "Email for our reply (optional)", "aria-label": "Your email (optional)", maxlength: "200", "data-1p-ignore": "", "data-lpignore": "true", "data-bwignore": "", "data-form-type": "other" });
481
487
  const row = el("div", { class: "ckw-msgr-box" });
482
488
  const text = el("textarea", { class: "ckw-textarea ckw-msgr-input", rows: "1", placeholder: "Write your message\u2026", "aria-label": "Message", maxlength: "4000" });
483
489
  const send = el("button", { type: "submit", class: "ckw-msgr-send", "aria-label": "Send" }, icon(I.up));
@@ -677,7 +683,7 @@ var build = (o) => {
677
683
  chip.addEventListener("click", () => go({ article: a.id }));
678
684
  li.append(chip);
679
685
  }
680
- li.append(el("span", { class: "ckw-msg-meta" }, `${m.from !== "visitor" ? `${whoLabel[m.from]} \xB7 ` : ""}${isPending ? "Sending\u2026" : timeAgo(m.at)}`));
686
+ li.append(el("span", { class: "ckw-msg-meta" }, m.from === "ai" ? agentFace() : null, `${m.from !== "visitor" ? `${whoLabel[m.from]} \xB7 ` : ""}${isPending ? "Sending\u2026" : timeAgo(m.at)}`));
681
687
  return li;
682
688
  };
683
689
  const articleRow = (a) => {
@@ -916,7 +922,7 @@ var build = (o) => {
916
922
  if (needEmail()) {
917
923
  if (emailOk()) email.removeAttribute("aria-invalid");
918
924
  else email.setAttribute("aria-invalid", "true");
919
- if (!email.isConnected) form.insertBefore(email, tray.isConnected ? tray : row);
925
+ if (!email.isConnected) row.insertBefore(email, text);
920
926
  } else email.remove();
921
927
  drawTray();
922
928
  send.disabled = !canSend();
@@ -1046,7 +1052,6 @@ var build = (o) => {
1046
1052
  view = v === "help" && !helpOn ? "home" : v;
1047
1053
  drawn = -1;
1048
1054
  previewGone = true;
1049
- hideTeaser(true);
1050
1055
  pop.toggleAttribute("data-still", still);
1051
1056
  enter(pop);
1052
1057
  if (was) replay(body, "ckw-msgr-enter");
@@ -1067,6 +1072,9 @@ var build = (o) => {
1067
1072
  drawFab();
1068
1073
  schedule();
1069
1074
  if (launcherOn) fab.focus();
1075
+ const fn = afterClose;
1076
+ afterClose = null;
1077
+ if (fn) setTimeout(fn, 220);
1070
1078
  }
1071
1079
  pop.addEventListener("click", () => amenuOpen() && closeAmenu());
1072
1080
  const onKey = (e) => {
@@ -1088,9 +1096,12 @@ var build = (o) => {
1088
1096
  open: (v) => show(v ?? "home"),
1089
1097
  close,
1090
1098
  toggle: () => open ? close() : show(),
1099
+ isOpen: () => open,
1100
+ onClose: (fn) => {
1101
+ afterClose = fn;
1102
+ },
1091
1103
  destroy: () => {
1092
1104
  clearTimeout(poll);
1093
- clearTimeout(teaserTimer);
1094
1105
  for (const t of leaving.values()) clearTimeout(t);
1095
1106
  ctrl?.abort();
1096
1107
  for (const p of picked) forget(p);