@mrrocket/sdk 0.9.0 → 0.11.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 +15 -0
- package/dist/api-client.d.ts +8 -0
- package/dist/api-client.js +13 -1
- package/dist/api-client.js.map +1 -1
- package/dist/browser/mrrocket-flows.js +2 -2
- package/dist/browser/mrrocket-messenger.js +85 -50
- package/dist/browser/mrrocket.js +1 -1
- package/dist/client.js +2 -0
- package/dist/client.js.map +1 -1
- package/dist/core.d.ts +1 -1
- package/dist/core.js +1 -1
- package/dist/core.js.map +1 -1
- package/dist/feedback.js +127 -22
- package/dist/feedback.js.map +1 -1
- package/dist/flows-ui.js +13 -1
- package/dist/flows-ui.js.map +1 -1
- package/dist/flows-web.js +1 -0
- package/dist/flows-web.js.map +1 -1
- package/dist/flows.d.ts +50 -5
- package/dist/flows.js +156 -34
- package/dist/flows.js.map +1 -1
- package/dist/messenger-ui.d.ts +2 -0
- package/dist/messenger-ui.js +54 -18
- package/dist/messenger-ui.js.map +1 -1
- package/dist/pick.d.ts +16 -0
- package/dist/pick.js +117 -0
- package/dist/pick.js.map +1 -0
- package/dist/react-native/index.d.cts +39 -3
- package/dist/react-native/index.d.ts +39 -3
- package/dist/react-native/index.js +353 -80
- package/dist/react-native/index.js.map +1 -1
- package/dist/styles-css.d.ts +1 -1
- package/dist/styles-css.js +83 -48
- package/dist/styles-css.js.map +1 -1
- package/package.json +5 -1
|
@@ -49,7 +49,7 @@ module.exports = __toCommonJS(native_exports);
|
|
|
49
49
|
var import_react3 = require("react");
|
|
50
50
|
|
|
51
51
|
// src/core.ts
|
|
52
|
-
var SDK_VERSION = "0.
|
|
52
|
+
var SDK_VERSION = "0.11.0";
|
|
53
53
|
var propOf = (person, name) => {
|
|
54
54
|
const want = name.trim().toLowerCase();
|
|
55
55
|
for (const [k, v] of Object.entries(person)) if (k.toLowerCase() === want) return v;
|
|
@@ -172,6 +172,16 @@ var textChanges = (config, distinctId, preview) => {
|
|
|
172
172
|
var newDistinctId = () => typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `ck_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`;
|
|
173
173
|
|
|
174
174
|
// src/api-client.ts
|
|
175
|
+
var replyLine = (t) => t === "minutes" ? "We usually reply in a few minutes" : t === "day" ? "We usually reply within a day" : "We usually reply in a few hours";
|
|
176
|
+
var inkOn = (hex) => {
|
|
177
|
+
const m = /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(hex);
|
|
178
|
+
if (!m) return "#ffffff";
|
|
179
|
+
const [r, g, b] = [m[1], m[2], m[3]].map((x) => {
|
|
180
|
+
const c = parseInt(x, 16) / 255;
|
|
181
|
+
return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
|
|
182
|
+
});
|
|
183
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b > 0.45 ? "#111214" : "#ffffff";
|
|
184
|
+
};
|
|
175
185
|
var ApiError = class extends Error {
|
|
176
186
|
constructor(message, status) {
|
|
177
187
|
super(message);
|
|
@@ -319,6 +329,19 @@ var safeUrl = (url) => {
|
|
|
319
329
|
const u = (url ?? "").trim();
|
|
320
330
|
return /^https?:\/\//i.test(u) || /^\/(?!\/)/.test(u) ? u : void 0;
|
|
321
331
|
};
|
|
332
|
+
var nodesOf = (f) => f.nodes ?? f.steps;
|
|
333
|
+
var waitMs = (w) => Math.max(0, w.amount) * (w.unit === "hours" ? 36e5 : 864e5);
|
|
334
|
+
var pageMatches = (pattern, path) => {
|
|
335
|
+
const p = pattern.trim();
|
|
336
|
+
const at = (path.split(/[?#]/)[0] || "/").replace(/\/+$/, "") || "/";
|
|
337
|
+
if (!p) return false;
|
|
338
|
+
if (p.endsWith("*")) {
|
|
339
|
+
const base = p.slice(0, -1).replace(/\/+$/, "");
|
|
340
|
+
return !base || at === base || at.startsWith(`${base}/`);
|
|
341
|
+
}
|
|
342
|
+
return at === (p.replace(/\/+$/, "") || "/");
|
|
343
|
+
};
|
|
344
|
+
var stepsIn = (nodes) => nodes.flatMap((n) => n.kind === "condition" ? [...stepsIn(n.yes), ...stepsIn(n.no)] : n.kind === "wait" ? [] : [n]);
|
|
322
345
|
var createFlows = (env) => {
|
|
323
346
|
let config = null;
|
|
324
347
|
let cancel = null;
|
|
@@ -333,25 +356,99 @@ var createFlows = (env) => {
|
|
|
333
356
|
const shown = /* @__PURE__ */ new Set();
|
|
334
357
|
const listeners = /* @__PURE__ */ new Set();
|
|
335
358
|
const auto = env.auto !== false;
|
|
359
|
+
const seenEvents = /* @__PURE__ */ new Set();
|
|
360
|
+
const now = () => env.now?.() ?? Date.now();
|
|
361
|
+
let timer = null;
|
|
336
362
|
const flows = () => config?.onboarding ?? [];
|
|
337
363
|
const flowById = (id) => id ? flows().find((f) => f.id === id) : void 0;
|
|
338
364
|
const prog = (id) => {
|
|
339
365
|
let p = progress.get(id);
|
|
340
|
-
if (!p) progress.set(id, p = { done: /* @__PURE__ */ new Set(), dismissed: false });
|
|
366
|
+
if (!p) progress.set(id, p = { done: /* @__PURE__ */ new Set(), dismissed: false, answers: /* @__PURE__ */ new Map(), at: /* @__PURE__ */ new Map(), reached: /* @__PURE__ */ new Map() });
|
|
341
367
|
return p;
|
|
342
368
|
};
|
|
369
|
+
let dirty = false;
|
|
370
|
+
const record = (props) => {
|
|
371
|
+
env.track(ONBOARDING_EVENT, props);
|
|
372
|
+
dirty = true;
|
|
373
|
+
};
|
|
374
|
+
const markDone = (p, id) => {
|
|
375
|
+
p.done.add(id);
|
|
376
|
+
p.at.set(id, now());
|
|
377
|
+
};
|
|
378
|
+
const decide = (c) => {
|
|
379
|
+
if (c.page?.trim()) {
|
|
380
|
+
const path = env.path?.();
|
|
381
|
+
return path === void 0 ? false : pageMatches(c.page, path);
|
|
382
|
+
}
|
|
383
|
+
if (c.event?.trim()) {
|
|
384
|
+
if (!known) return void 0;
|
|
385
|
+
for (const e of seenEvents) if (matchesTrigger(c.event, e)) return true;
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
return false;
|
|
389
|
+
};
|
|
390
|
+
const walkLine = (flow, line, p, live, before = 0, last) => {
|
|
391
|
+
for (let i = 0; i < line.length; i++) {
|
|
392
|
+
const n = line[i];
|
|
393
|
+
if (n.kind === "wait") {
|
|
394
|
+
if (p.done.has(n.id)) {
|
|
395
|
+
last = p.at.get(n.id) ?? last;
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
let since = p.reached.get(n.id);
|
|
399
|
+
if (since === void 0) {
|
|
400
|
+
if (!live) return { at: "pending" };
|
|
401
|
+
since = last ?? now();
|
|
402
|
+
p.reached.set(n.id, since);
|
|
403
|
+
record({ flow: flow.id, step: n.id, kind: "wait", action: "shown" });
|
|
404
|
+
}
|
|
405
|
+
const until = since + waitMs(n);
|
|
406
|
+
if (now() < until) return { at: "wait", until };
|
|
407
|
+
if (!live) return { at: "pending" };
|
|
408
|
+
markDone(p, n.id);
|
|
409
|
+
record({ flow: flow.id, step: n.id, kind: "wait", action: "completed" });
|
|
410
|
+
last = until;
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
if (n.kind === "condition") {
|
|
414
|
+
let answer = p.answers.get(n.id);
|
|
415
|
+
if (answer === void 0) {
|
|
416
|
+
if (!live) return { at: "pending" };
|
|
417
|
+
answer = decide(n);
|
|
418
|
+
if (answer === void 0) return { at: "pending" };
|
|
419
|
+
p.answers.set(n.id, answer);
|
|
420
|
+
record({ flow: flow.id, step: n.id, kind: "condition", action: "answered", answer: answer ? "yes" : "no" });
|
|
421
|
+
}
|
|
422
|
+
return walkLine(flow, answer ? n.yes : n.no, p, live, before, last);
|
|
423
|
+
}
|
|
424
|
+
if (!p.done.has(n.id)) return { at: "step", step: n, line, index: i, before };
|
|
425
|
+
last = p.at.get(n.id) ?? last;
|
|
426
|
+
before++;
|
|
427
|
+
}
|
|
428
|
+
return { at: "end" };
|
|
429
|
+
};
|
|
343
430
|
const finished = (f) => {
|
|
344
431
|
const p = progress.get(f.id);
|
|
345
|
-
return !!p && (p.dismissed || f
|
|
432
|
+
return !!p && (p.dismissed || walkLine(f, nodesOf(f), p, false).at === "end");
|
|
346
433
|
};
|
|
347
434
|
const keyOf = (pid) => `${PROGRESS_KEY}:${pid ?? "visitor"}`;
|
|
435
|
+
const eventsKeyOf = (pid) => `${PROGRESS_KEY}:events:${pid ?? "visitor"}`;
|
|
348
436
|
const save = () => {
|
|
437
|
+
dirty = false;
|
|
349
438
|
const store = env.storage?.();
|
|
350
439
|
if (!store) return;
|
|
351
440
|
const out = {};
|
|
352
|
-
for (const [id, p] of progress)
|
|
441
|
+
for (const [id, p] of progress)
|
|
442
|
+
out[id] = {
|
|
443
|
+
done: [...p.done],
|
|
444
|
+
...p.dismissed ? { dismissed: true } : {},
|
|
445
|
+
...p.answers.size ? { answers: Object.fromEntries([...p.answers].map(([k, v]) => [k, v ? "yes" : "no"])) } : {},
|
|
446
|
+
...p.at.size ? { at: Object.fromEntries(p.at) } : {},
|
|
447
|
+
...p.reached.size ? { reached: Object.fromEntries(p.reached) } : {}
|
|
448
|
+
};
|
|
353
449
|
try {
|
|
354
450
|
store.set(keyOf(env.personId()), JSON.stringify(out));
|
|
451
|
+
if (seenEvents.size) store.set(eventsKeyOf(env.personId()), JSON.stringify([...seenEvents].slice(-200)));
|
|
355
452
|
} catch {
|
|
356
453
|
}
|
|
357
454
|
};
|
|
@@ -360,23 +457,55 @@ var createFlows = (env) => {
|
|
|
360
457
|
const p = prog(id);
|
|
361
458
|
for (const d of s.done ?? []) p.done.add(d);
|
|
362
459
|
if (s.dismissed) p.dismissed = true;
|
|
460
|
+
for (const [k, v] of Object.entries(s.answers ?? {})) if (!p.answers.has(k)) p.answers.set(k, v === "yes");
|
|
461
|
+
for (const [k, v] of Object.entries(s.at ?? {})) if (typeof v === "number" && !p.at.has(k)) p.at.set(k, v);
|
|
462
|
+
for (const [k, v] of Object.entries(s.reached ?? {})) if (typeof v === "number" && (!p.reached.has(k) || v < p.reached.get(k))) p.reached.set(k, v);
|
|
463
|
+
}
|
|
464
|
+
};
|
|
465
|
+
const wakeAt = (until) => {
|
|
466
|
+
if (timer) clearTimeout(timer);
|
|
467
|
+
timer = null;
|
|
468
|
+
const ms = until - now();
|
|
469
|
+
if (ms > 0 && ms <= 864e5) {
|
|
470
|
+
timer = setTimeout(() => (timer = null, emit()), ms + 50);
|
|
471
|
+
timer.unref?.();
|
|
363
472
|
}
|
|
364
473
|
};
|
|
474
|
+
let holding = false;
|
|
365
475
|
const onboardingView = () => {
|
|
476
|
+
holding = false;
|
|
366
477
|
const flow = flowById(active);
|
|
367
478
|
if (!flow) return null;
|
|
368
479
|
const p = prog(flow.id);
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
480
|
+
if (p.dismissed) return null;
|
|
481
|
+
const w = walkLine(flow, nodesOf(flow), p, true);
|
|
482
|
+
if (dirty) save();
|
|
483
|
+
if (w.at === "wait") wakeAt(w.until);
|
|
484
|
+
holding = w.at === "wait" || w.at === "pending";
|
|
485
|
+
if (w.at !== "step") return null;
|
|
486
|
+
const { step, line, index } = w;
|
|
487
|
+
const isStep = (n) => !!n && n.kind !== "wait" && n.kind !== "condition";
|
|
372
488
|
if (step.kind === "checklist") {
|
|
373
|
-
let from =
|
|
374
|
-
while (from > 0 &&
|
|
375
|
-
let to =
|
|
376
|
-
while (to + 1 <
|
|
377
|
-
|
|
489
|
+
let from = index;
|
|
490
|
+
while (from > 0 && isStep(line[from - 1]) && line[from - 1].kind === "checklist") from--;
|
|
491
|
+
let to = index;
|
|
492
|
+
while (to + 1 < line.length && isStep(line[to + 1]) && line[to + 1].kind === "checklist") to++;
|
|
493
|
+
const items = line.slice(from, to + 1).filter(isStep);
|
|
494
|
+
for (const i of items)
|
|
495
|
+
if (!p.done.has(i.id) && !shown.has(`s:${i.id}`)) {
|
|
496
|
+
shown.add(`s:${i.id}`);
|
|
497
|
+
env.track(ONBOARDING_EVENT, { flow: flow.id, step: i.id, kind: "checklist", action: "shown" });
|
|
498
|
+
}
|
|
499
|
+
return { type: "checklist", flow, items: items.map((s) => ({ step: s, done: p.done.has(s.id) })) };
|
|
500
|
+
}
|
|
501
|
+
if (!shown.has(`s:${step.id}`)) {
|
|
502
|
+
shown.add(`s:${step.id}`);
|
|
503
|
+
env.track(ONBOARDING_EVENT, { flow: flow.id, step: step.id, kind: step.kind, action: "shown" });
|
|
378
504
|
}
|
|
379
|
-
|
|
505
|
+
const rest = line.slice(index + 1);
|
|
506
|
+
const fork = rest.findIndex((n) => n.kind === "condition");
|
|
507
|
+
const ahead = (fork < 0 ? rest : rest.slice(0, fork)).filter(isStep).length;
|
|
508
|
+
return { type: "step", flow, step, index: w.before, total: w.before + 1 + ahead, last: !ahead && fork < 0 };
|
|
380
509
|
};
|
|
381
510
|
const view = () => {
|
|
382
511
|
if (cancel) {
|
|
@@ -396,22 +525,13 @@ var createFlows = (env) => {
|
|
|
396
525
|
}
|
|
397
526
|
const ob = onboardingView();
|
|
398
527
|
if (ob) return ob;
|
|
399
|
-
if (active) active = null;
|
|
528
|
+
if (active && !holding) active = null;
|
|
400
529
|
const m = messages.find((x) => !handled.has(x.id));
|
|
401
530
|
return m ? { type: "message", message: m } : null;
|
|
402
531
|
};
|
|
403
532
|
const emit = () => {
|
|
404
533
|
const v = view();
|
|
405
|
-
if (v?.type === "
|
|
406
|
-
shown.add(`s:${v.step.id}`);
|
|
407
|
-
env.track(ONBOARDING_EVENT, { flow: v.flow.id, step: v.step.id, kind: v.step.kind, action: "shown" });
|
|
408
|
-
} else if (v?.type === "checklist") {
|
|
409
|
-
for (const i of v.items)
|
|
410
|
-
if (!i.done && !shown.has(`s:${i.step.id}`)) {
|
|
411
|
-
shown.add(`s:${i.step.id}`);
|
|
412
|
-
env.track(ONBOARDING_EVENT, { flow: v.flow.id, step: i.step.id, kind: "checklist", action: "shown" });
|
|
413
|
-
}
|
|
414
|
-
} else if (v?.type === "message" && !shown.has(`m:${v.message.id}`)) {
|
|
534
|
+
if (v?.type === "message" && !shown.has(`m:${v.message.id}`)) {
|
|
415
535
|
shown.add(`m:${v.message.id}`);
|
|
416
536
|
env.track(INAPP_EVENT, { message: v.message.id, journey: v.message.journey, action: "shown" });
|
|
417
537
|
}
|
|
@@ -433,13 +553,14 @@ var createFlows = (env) => {
|
|
|
433
553
|
const autoStart = () => {
|
|
434
554
|
if (!auto || active || !known) return;
|
|
435
555
|
if (!env.personId() && !env.storage?.()) return;
|
|
436
|
-
const next = flows().find((f) => startsOnLoad(f.trigger) && f.
|
|
556
|
+
const next = flows().find((f) => startsOnLoad(f.trigger) && nodesOf(f).length && !finished(f));
|
|
437
557
|
if (next) start(next);
|
|
438
558
|
};
|
|
439
559
|
const refresh = () => {
|
|
440
560
|
const pid = env.personId();
|
|
441
561
|
if (progressFor !== null && progressFor !== pid) {
|
|
442
562
|
progress.clear();
|
|
563
|
+
seenEvents.clear();
|
|
443
564
|
handled.clear();
|
|
444
565
|
active = null;
|
|
445
566
|
loadedFor = void 0;
|
|
@@ -451,6 +572,10 @@ var createFlows = (env) => {
|
|
|
451
572
|
try {
|
|
452
573
|
const raw = await store.get(keyOf(pid));
|
|
453
574
|
if (raw) merge(JSON.parse(raw));
|
|
575
|
+
const seen = await store.get(eventsKeyOf(pid));
|
|
576
|
+
if (seen) {
|
|
577
|
+
for (const e of JSON.parse(seen)) if (typeof e === "string") seenEvents.add(e);
|
|
578
|
+
}
|
|
454
579
|
} catch {
|
|
455
580
|
}
|
|
456
581
|
}
|
|
@@ -460,6 +585,7 @@ var createFlows = (env) => {
|
|
|
460
585
|
const state = await env.fetchInApp(pid).catch(() => null);
|
|
461
586
|
if (state && env.personId() === pid) {
|
|
462
587
|
merge(state.onboarding);
|
|
588
|
+
for (const e of state.events ?? []) if (typeof e === "string") seenEvents.add(eventSlug(e));
|
|
463
589
|
messages = (state.messages ?? []).filter((m) => m && m.id && m.title);
|
|
464
590
|
}
|
|
465
591
|
}
|
|
@@ -536,29 +662,32 @@ var createFlows = (env) => {
|
|
|
536
662
|
refresh,
|
|
537
663
|
onEvent: (name) => {
|
|
538
664
|
if (!name || name.startsWith("$")) return;
|
|
665
|
+
const slug = eventSlug(name);
|
|
666
|
+
const fresh = !!slug && !seenEvents.has(slug);
|
|
667
|
+
if (fresh) seenEvents.add(slug);
|
|
539
668
|
const flow = flowById(active);
|
|
540
669
|
let ticked = false;
|
|
541
670
|
if (flow) {
|
|
542
671
|
const p = prog(flow.id);
|
|
543
|
-
for (const s of flow
|
|
672
|
+
for (const s of stepsIn(nodesOf(flow)))
|
|
544
673
|
if (s.kind === "checklist" && s.event && !p.done.has(s.id) && matchesTrigger(s.event, name)) {
|
|
545
|
-
p
|
|
674
|
+
markDone(p, s.id);
|
|
546
675
|
ticked = true;
|
|
547
676
|
env.track(ONBOARDING_EVENT, { flow: flow.id, step: s.id, kind: s.kind, action: "completed" });
|
|
548
677
|
}
|
|
549
678
|
}
|
|
550
|
-
if (ticked) {
|
|
679
|
+
if (ticked || fresh && flow) {
|
|
551
680
|
save();
|
|
552
681
|
emit();
|
|
553
|
-
}
|
|
682
|
+
} else if (fresh) save();
|
|
554
683
|
if (!auto || !env.personId() && !env.storage?.()) return;
|
|
555
|
-
const next = flows().find((f) => f.
|
|
684
|
+
const next = flows().find((f) => nodesOf(f).length && matchesTrigger(f.trigger, name) && !finished(f));
|
|
556
685
|
if (next) start(next);
|
|
557
686
|
},
|
|
558
687
|
openCancelFlow,
|
|
559
688
|
startOnboarding: (id) => {
|
|
560
|
-
const f = id ? flowById(id) : flows().find((x) => x.
|
|
561
|
-
if (!f || !f.
|
|
689
|
+
const f = id ? flowById(id) : flows().find((x) => nodesOf(x).length && !finished(x));
|
|
690
|
+
if (!f || !nodesOf(f).length) return false;
|
|
562
691
|
const p = prog(f.id);
|
|
563
692
|
p.dismissed = false;
|
|
564
693
|
return start(f);
|
|
@@ -629,7 +758,7 @@ var createFlows = (env) => {
|
|
|
629
758
|
next: () => {
|
|
630
759
|
const v = onboardingView();
|
|
631
760
|
if (v?.type !== "step") return;
|
|
632
|
-
prog(v.flow.id)
|
|
761
|
+
markDone(prog(v.flow.id), v.step.id);
|
|
633
762
|
env.track(ONBOARDING_EVENT, { flow: v.flow.id, step: v.step.id, kind: v.step.kind, action: "completed" });
|
|
634
763
|
save();
|
|
635
764
|
emit();
|
|
@@ -639,7 +768,7 @@ var createFlows = (env) => {
|
|
|
639
768
|
if (v?.type !== "checklist") return;
|
|
640
769
|
const item = v.items.find((i) => i.step.id === stepId);
|
|
641
770
|
if (!item || item.done) return;
|
|
642
|
-
prog(v.flow.id)
|
|
771
|
+
markDone(prog(v.flow.id), stepId);
|
|
643
772
|
env.track(ONBOARDING_EVENT, { flow: v.flow.id, step: stepId, kind: "checklist", action: "completed" });
|
|
644
773
|
save();
|
|
645
774
|
emit();
|
|
@@ -2369,6 +2498,35 @@ var buzz = () => {
|
|
|
2369
2498
|
}
|
|
2370
2499
|
};
|
|
2371
2500
|
var teamOf = (t) => (t?.messages ?? []).filter((m) => m.from !== "visitor");
|
|
2501
|
+
var svg = null;
|
|
2502
|
+
try {
|
|
2503
|
+
svg = require("react-native-svg");
|
|
2504
|
+
} catch {
|
|
2505
|
+
svg = null;
|
|
2506
|
+
}
|
|
2507
|
+
var GLYPH = {
|
|
2508
|
+
chat: "M2.5 4.5a2 2 0 0 1 2-2h7a2 2 0 0 1 2 2v4.5a2 2 0 0 1-2 2H7l-3 2.5V11a2 2 0 0 1-1.5-2z",
|
|
2509
|
+
home: "M2.5 7 8 2.5 13.5 7v6a1 1 0 0 1-1 1h-3v-4h-3v4h-3a1 1 0 0 1-1-1z",
|
|
2510
|
+
help: "M8 14.5A6.5 6.5 0 1 0 8 1.5a6.5 6.5 0 0 0 0 13zM6.2 6.2a1.9 1.9 0 1 1 2.6 1.8c-.5.2-.8.6-.8 1.1v.4M8 11.6v.1",
|
|
2511
|
+
send: "M2.5 8h10M8.5 3.5 13 8l-4.5 4.5",
|
|
2512
|
+
up: "M8 13V3M3.5 7.5 8 3l4.5 4.5",
|
|
2513
|
+
next: "M6 3.5 10.5 8 6 12.5",
|
|
2514
|
+
search: "M7 11.5a4.5 4.5 0 1 0 0-9 4.5 4.5 0 0 0 0 9zM10.5 10.5l3 3",
|
|
2515
|
+
cross: "m4 4 8 8M12 4l-8 8"
|
|
2516
|
+
};
|
|
2517
|
+
var FALLBACK = { chat: "\u{1F4AC}", home: "\u2302", help: "?", send: "\u2192", up: "\u2191", next: "\u203A", search: "\u2315", cross: "\xD7" };
|
|
2518
|
+
var glyph = (name, color, size = 20) => {
|
|
2519
|
+
const Svg = svg?.Svg ?? svg?.default;
|
|
2520
|
+
if (!svg || !Svg) return (0, import_react2.createElement)(RN3.Text, { style: { color, fontSize: Math.round(size * 0.85), lineHeight: size + 2, textAlign: "center", minWidth: size } }, FALLBACK[name]);
|
|
2521
|
+
return (0, import_react2.createElement)(Svg, { width: size, height: size, viewBox: "0 0 16 16", fill: "none" }, (0, import_react2.createElement)(svg.Path, { d: GLYPH[name], stroke: color, strokeWidth: 1.7, strokeLinecap: "round", strokeLinejoin: "round", fill: "none" }));
|
|
2522
|
+
};
|
|
2523
|
+
var alpha = (hex, a) => /^#[0-9a-f]{6}$/i.test(hex) ? `${hex}${Math.round(a * 255).toString(16).padStart(2, "0")}` : hex;
|
|
2524
|
+
var teamMark = (title, bg, fg, size = 36) => (0, import_react2.createElement)(
|
|
2525
|
+
RN3.View,
|
|
2526
|
+
{ style: { width: size, height: size, borderRadius: size / 2, backgroundColor: bg, alignItems: "center", justifyContent: "center" } },
|
|
2527
|
+
(0, import_react2.createElement)(RN3.Text, { style: { color: fg, fontSize: Math.round(size * 0.42), fontWeight: "700" } }, (title.trim()[0] ?? "?").toUpperCase())
|
|
2528
|
+
);
|
|
2529
|
+
var lift = { shadowColor: "#101218", shadowOpacity: 0.07, shadowRadius: 14, shadowOffset: { width: 0, height: 4 }, elevation: 2 };
|
|
2372
2530
|
var useChat = (client, o, open, view) => {
|
|
2373
2531
|
const [thread, setThread] = (0, import_react2.useState)(null);
|
|
2374
2532
|
const [loaded, setLoaded] = (0, import_react2.useState)(false);
|
|
@@ -2570,55 +2728,102 @@ var MessengerSheet = ({
|
|
|
2570
2728
|
setPending(null);
|
|
2571
2729
|
}
|
|
2572
2730
|
};
|
|
2731
|
+
const ink = inkOn(p.accent);
|
|
2732
|
+
const dark = p.bg === DARK.bg;
|
|
2733
|
+
const canvas = dark ? p.bg : p.soft;
|
|
2734
|
+
const raised = dark ? p.soft : p.bg;
|
|
2735
|
+
const title = o.title ?? "Chat with us";
|
|
2736
|
+
const reply = replyLine(o.replyTime);
|
|
2573
2737
|
const bubble = (m, isPending = false) => {
|
|
2574
2738
|
const mine = m.from === "visitor";
|
|
2575
2739
|
return (0, import_react2.createElement)(
|
|
2576
2740
|
RN3.View,
|
|
2577
2741
|
{ key: m.id, style: { alignSelf: mine ? "flex-end" : "flex-start", maxWidth: "82%", gap: 4 } },
|
|
2578
|
-
(0, import_react2.createElement)(
|
|
2742
|
+
(0, import_react2.createElement)(
|
|
2743
|
+
RN3.View,
|
|
2744
|
+
{
|
|
2745
|
+
style: {
|
|
2746
|
+
backgroundColor: mine ? p.accent : dark ? p.soft : "#eeeff1",
|
|
2747
|
+
borderRadius: 18,
|
|
2748
|
+
borderBottomRightRadius: mine ? 6 : 18,
|
|
2749
|
+
borderBottomLeftRadius: mine ? 18 : 6,
|
|
2750
|
+
paddingHorizontal: 14,
|
|
2751
|
+
paddingVertical: 9,
|
|
2752
|
+
opacity: isPending ? 0.7 : 1
|
|
2753
|
+
}
|
|
2754
|
+
},
|
|
2755
|
+
k.text(m.body, { color: mine ? ink : p.fg })
|
|
2756
|
+
),
|
|
2579
2757
|
...(m.articles ?? []).map(
|
|
2580
2758
|
(a) => (0, import_react2.createElement)(
|
|
2581
2759
|
RN3.Pressable,
|
|
2582
|
-
{ key: a.id, onPress: () => setView({ article: a.id }), accessibilityRole: "link", style: { borderWidth: 1, borderColor: p.line, borderRadius:
|
|
2760
|
+
{ key: a.id, onPress: () => setView({ article: a.id }), accessibilityRole: "link", style: { borderWidth: 1, borderColor: p.line, borderRadius: 12, paddingHorizontal: 10, paddingVertical: 7 } },
|
|
2583
2761
|
k.text(`\u{1F4C4} ${a.title}`, { fontSize: 13 })
|
|
2584
2762
|
)
|
|
2585
2763
|
),
|
|
2586
|
-
m.at ? k.muted(`${mine ? "" : `${whoLabel[m.from]} \xB7 `}${isPending ? "Sending\u2026" : timeAgo(m.at)}`, { fontSize: 11, textAlign: mine ? "right" : "left" }) : null
|
|
2764
|
+
m.at ? k.muted(`${mine ? "" : `${whoLabel[m.from]} \xB7 `}${isPending ? "Sending\u2026" : timeAgo(m.at)}`, { fontSize: 11, textAlign: mine ? "right" : "left", paddingHorizontal: 6 }) : null
|
|
2587
2765
|
);
|
|
2588
2766
|
};
|
|
2589
2767
|
const row = (a) => (0, import_react2.createElement)(
|
|
2590
2768
|
RN3.Pressable,
|
|
2591
|
-
{ key: a.id, onPress: () => setView({ article: a.id }), accessibilityRole: "button", style: { flexDirection: "row", alignItems: "center", paddingVertical: 11, paddingHorizontal:
|
|
2769
|
+
{ key: a.id, onPress: () => setView({ article: a.id }), accessibilityRole: "button", style: { flexDirection: "row", alignItems: "center", gap: 8, paddingVertical: 11, paddingHorizontal: 8 } },
|
|
2592
2770
|
k.text(a.title, { flex: 1 }),
|
|
2593
|
-
|
|
2771
|
+
glyph("next", p.accent, 14)
|
|
2772
|
+
);
|
|
2773
|
+
const card = (children, style = {}) => (0, import_react2.createElement)(RN3.View, { style: { backgroundColor: raised, borderRadius: 16, padding: 16, ...dark ? { borderWidth: 1, borderColor: p.line } : lift, ...style } }, ...children);
|
|
2774
|
+
const searchRow = (onPress) => (0, import_react2.createElement)(
|
|
2775
|
+
RN3.Pressable,
|
|
2776
|
+
{ key: "s", onPress, accessibilityRole: "search", style: { flexDirection: "row", alignItems: "center", height: 44, borderRadius: 12, paddingHorizontal: 14, backgroundColor: canvas } },
|
|
2777
|
+
k.muted("Search for help", { flex: 1, fontSize: 15 }),
|
|
2778
|
+
glyph("search", p.accent, 16)
|
|
2594
2779
|
);
|
|
2595
|
-
const
|
|
2596
|
-
const search = k.field({ value: query, onChange: setQuery, placeholder: "Search for help", max: 200 });
|
|
2780
|
+
const search = k.field({ value: query, onChange: setQuery, placeholder: "Search for help", max: 200, style: { borderWidth: 0, borderRadius: 12, backgroundColor: raised, ...dark ? {} : lift } });
|
|
2597
2781
|
const last = thread?.messages.at(-1);
|
|
2598
2782
|
const showHelp = helpOn && arts.any !== false;
|
|
2599
2783
|
let content;
|
|
2600
2784
|
if (view === "home")
|
|
2601
2785
|
content = (0, import_react2.createElement)(
|
|
2602
2786
|
RN3.ScrollView,
|
|
2603
|
-
{ key: "home", style: { flex: 1, backgroundColor:
|
|
2604
|
-
(0, import_react2.createElement)(RN3.
|
|
2787
|
+
{ key: "home", style: { flex: 1, backgroundColor: canvas }, contentContainerStyle: { paddingBottom: 24 }, keyboardShouldPersistTaps: "handled" },
|
|
2788
|
+
(0, import_react2.createElement)(RN3.View, { style: { backgroundColor: p.accent, paddingHorizontal: 22, paddingTop: 4, paddingBottom: 64 } }, (0, import_react2.createElement)(RN3.Text, { style: { color: ink, fontSize: 28, fontWeight: "700", letterSpacing: -0.4, lineHeight: 34 } }, greeting)),
|
|
2605
2789
|
(0, import_react2.createElement)(
|
|
2606
|
-
RN3.
|
|
2607
|
-
{
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2790
|
+
RN3.View,
|
|
2791
|
+
{ style: { marginTop: -48, paddingHorizontal: 16, gap: 12 } },
|
|
2792
|
+
last ? (0, import_react2.createElement)(
|
|
2793
|
+
RN3.Pressable,
|
|
2794
|
+
{ key: "recent", onPress: () => setView("messages"), accessibilityRole: "button" },
|
|
2795
|
+
card([
|
|
2796
|
+
k.muted("Recent message", { fontSize: 12, fontWeight: "600", marginBottom: 10 }),
|
|
2797
|
+
(0, import_react2.createElement)(
|
|
2798
|
+
RN3.View,
|
|
2799
|
+
{ key: "r", style: { flexDirection: "row", alignItems: "center", gap: 12 } },
|
|
2800
|
+
teamMark(title, p.accent, ink),
|
|
2801
|
+
(0, import_react2.createElement)(RN3.View, { style: { flex: 1, gap: 2 } }, (0, import_react2.createElement)(RN3.Text, { numberOfLines: 1, style: { color: p.fg, fontSize: 15 } }, last.body), k.muted(`${last.from === "visitor" ? "You" : whoLabel[last.from]} \xB7 ${timeAgo(last.at)}`, { fontSize: 12 })),
|
|
2802
|
+
chat.unseen.length ? (0, import_react2.createElement)(RN3.View, { style: { minWidth: 20, height: 20, borderRadius: 10, paddingHorizontal: 6, backgroundColor: p.danger, alignItems: "center", justifyContent: "center" } }, k.text(String(chat.unseen.length), { color: "#fff", fontSize: 12, fontWeight: "700" })) : glyph("next", p.muted, 14)
|
|
2803
|
+
)
|
|
2804
|
+
])
|
|
2805
|
+
) : null,
|
|
2806
|
+
(0, import_react2.createElement)(
|
|
2807
|
+
RN3.Pressable,
|
|
2808
|
+
{ key: "send", onPress: () => setView("messages"), accessibilityRole: "button" },
|
|
2809
|
+
card(
|
|
2810
|
+
[
|
|
2811
|
+
(0, import_react2.createElement)(RN3.View, { key: "t", style: { flex: 1, gap: 2 } }, k.text("Send us a message", { fontWeight: "700", fontSize: 16 }), k.muted(reply)),
|
|
2812
|
+
(0, import_react2.createElement)(RN3.View, { key: "g", style: { width: 36, height: 36, borderRadius: 18, backgroundColor: alpha(p.accent, 0.12), alignItems: "center", justifyContent: "center" } }, glyph("send", p.accent, 18))
|
|
2813
|
+
],
|
|
2814
|
+
{ flexDirection: "row", alignItems: "center", gap: 12 }
|
|
2815
|
+
)
|
|
2816
|
+
),
|
|
2817
|
+
showHelp ? card([searchRow(() => setView("help")), ...(arts.list ?? []).slice(0, 4).map(row)], { padding: 8, gap: 2 }) : null
|
|
2818
|
+
)
|
|
2614
2819
|
);
|
|
2615
2820
|
else if (view === "messages")
|
|
2616
2821
|
content = (0, import_react2.createElement)(
|
|
2617
2822
|
RN3.View,
|
|
2618
|
-
{ key: "messages", style: { flex: 1 } },
|
|
2823
|
+
{ key: "messages", style: { flex: 1, backgroundColor: p.bg } },
|
|
2619
2824
|
(0, import_react2.createElement)(
|
|
2620
2825
|
RN3.ScrollView,
|
|
2621
|
-
{ ref: scroll, style: { flex: 1 }, contentContainerStyle: { padding: 16, gap:
|
|
2826
|
+
{ ref: scroll, style: { flex: 1 }, contentContainerStyle: { padding: 16, gap: 12 } },
|
|
2622
2827
|
bubble({ id: "greeting", from: "team", body: greeting, at: "" }),
|
|
2623
2828
|
!chat.loaded ? k.muted("Loading\u2026") : null,
|
|
2624
2829
|
...(thread?.messages ?? []).map((m) => bubble(m)),
|
|
@@ -2627,14 +2832,24 @@ var MessengerSheet = ({
|
|
|
2627
2832
|
),
|
|
2628
2833
|
(0, import_react2.createElement)(
|
|
2629
2834
|
RN3.View,
|
|
2630
|
-
{ style: {
|
|
2835
|
+
{ style: { paddingHorizontal: 12, paddingTop: 8, paddingBottom: 10, gap: 8 } },
|
|
2631
2836
|
chat.error ? k.text(chat.error, { color: p.danger, fontSize: 12 }) : null,
|
|
2632
|
-
needEmail ? k.field({ value: email, onChange: setEmail, placeholder: "Your email (optional), so we can follow up", email: true, max: 200, style: emailOk ?
|
|
2837
|
+
needEmail ? k.field({ value: email, onChange: setEmail, placeholder: "Your email (optional), so we can follow up", email: true, max: 200, style: { borderWidth: emailOk ? 0 : 1, borderColor: p.danger, borderRadius: 12, backgroundColor: canvas } }) : null,
|
|
2633
2838
|
(0, import_react2.createElement)(
|
|
2634
2839
|
RN3.View,
|
|
2635
|
-
{ style: { flexDirection: "row",
|
|
2636
|
-
k.field({ value: body, onChange: setBody, placeholder: "Write a message\u2026", multiline: true, max: 4e3, style: { flex: 1, minHeight:
|
|
2637
|
-
|
|
2840
|
+
{ style: { flexDirection: "row", alignItems: "flex-end", gap: 6, borderWidth: 1, borderColor: p.line, borderRadius: 22, paddingVertical: 5, paddingRight: 5, paddingLeft: 16, backgroundColor: p.bg } },
|
|
2841
|
+
k.field({ value: body, onChange: setBody, placeholder: "Write a message\u2026", multiline: true, max: 4e3, style: { flex: 1, minHeight: 34, maxHeight: 120, borderWidth: 0, paddingHorizontal: 0, paddingVertical: 7, backgroundColor: "transparent" } }),
|
|
2842
|
+
(0, import_react2.createElement)(
|
|
2843
|
+
RN3.Pressable,
|
|
2844
|
+
{
|
|
2845
|
+
onPress: () => void send(),
|
|
2846
|
+
disabled: !body.trim() || !!pending || !emailOk,
|
|
2847
|
+
accessibilityRole: "button",
|
|
2848
|
+
accessibilityLabel: "Send",
|
|
2849
|
+
style: { width: 34, height: 34, borderRadius: 17, alignItems: "center", justifyContent: "center", backgroundColor: !body.trim() || !!pending || !emailOk ? p.line : p.accent }
|
|
2850
|
+
},
|
|
2851
|
+
glyph("up", !body.trim() || !!pending || !emailOk ? p.muted : ink, 18)
|
|
2852
|
+
)
|
|
2638
2853
|
)
|
|
2639
2854
|
)
|
|
2640
2855
|
);
|
|
@@ -2643,11 +2858,11 @@ var MessengerSheet = ({
|
|
|
2643
2858
|
for (const a of arts.list ?? []) groups.set(a.collection, [...groups.get(a.collection) ?? [], a]);
|
|
2644
2859
|
content = (0, import_react2.createElement)(
|
|
2645
2860
|
RN3.ScrollView,
|
|
2646
|
-
{ key: "help", style: { flex: 1, backgroundColor:
|
|
2861
|
+
{ key: "help", style: { flex: 1, backgroundColor: canvas }, contentContainerStyle: { padding: 16, gap: 12 }, keyboardShouldPersistTaps: "handled" },
|
|
2647
2862
|
search,
|
|
2648
2863
|
arts.list === null ? k.muted("Loading\u2026") : null,
|
|
2649
2864
|
arts.list?.length === 0 ? (0, import_react2.createElement)(RN3.View, { style: { gap: 10, alignItems: "center", paddingVertical: 24 } }, k.muted(query.trim() ? `Nothing found for \u201C${query.trim()}\u201D.` : "No help articles yet."), k.btn("Send us a message", "primary", () => setView("messages"))) : null,
|
|
2650
|
-
...query.trim() ? arts.list?.length ? [card((arts.list ?? []).map(row))] : [] : [...groups].map(([name, items]) => (0, import_react2.createElement)(RN3.View, { key: name, style: { gap: 6 } }, k.muted(`${name} \xB7 ${items.length}
|
|
2865
|
+
...query.trim() ? arts.list?.length ? [card((arts.list ?? []).map(row), { padding: 8 })] : [] : [...groups].map(([name, items]) => (0, import_react2.createElement)(RN3.View, { key: name, style: { gap: 6 } }, k.muted(`${name} \xB7 ${items.length}`, { fontSize: 12, fontWeight: "600", paddingHorizontal: 2 }), card(items.map(row), { padding: 8 })))
|
|
2651
2866
|
);
|
|
2652
2867
|
} else
|
|
2653
2868
|
content = (0, import_react2.createElement)(
|
|
@@ -2656,25 +2871,44 @@ var MessengerSheet = ({
|
|
|
2656
2871
|
(0, import_react2.createElement)(ArticleView, { client, p, id: view.article, onAsk: () => setView("messages") })
|
|
2657
2872
|
);
|
|
2658
2873
|
const current = typeof view === "string" ? view : "help";
|
|
2659
|
-
const tab = (v, name,
|
|
2874
|
+
const tab = (v, name, icon, badge = 0) => (0, import_react2.createElement)(
|
|
2660
2875
|
RN3.Pressable,
|
|
2661
|
-
{ key: v, onPress: () => setView(v), accessibilityRole: "tab", accessibilityState: { selected: current === v }, style: { flex: 1, alignItems: "center", paddingTop: 8, paddingBottom: 6, gap:
|
|
2662
|
-
|
|
2663
|
-
k.text(name, { fontSize: 12, fontWeight: "600", color: current === v ? p.
|
|
2664
|
-
badge ? (0, import_react2.createElement)(RN3.View, { style: { position: "absolute", top: 4, right: "
|
|
2876
|
+
{ key: v, onPress: () => setView(v), accessibilityRole: "tab", accessibilityState: { selected: current === v }, style: { flex: 1, alignItems: "center", paddingTop: 8, paddingBottom: 6, gap: 3 } },
|
|
2877
|
+
glyph(icon, current === v ? p.accent : p.muted, 22),
|
|
2878
|
+
k.text(name, { fontSize: 12, fontWeight: "600", color: current === v ? p.accent : p.muted }),
|
|
2879
|
+
badge ? (0, import_react2.createElement)(RN3.View, { style: { position: "absolute", top: 4, right: "28%", minWidth: 18, height: 18, borderRadius: 9, backgroundColor: p.danger, alignItems: "center", justifyContent: "center" } }, k.text(String(Math.min(badge, 9)), { color: "#fff", fontSize: 11, fontWeight: "700" })) : null
|
|
2665
2880
|
);
|
|
2666
|
-
const
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2881
|
+
const onHome = view === "home";
|
|
2882
|
+
const headFg = onHome ? ink : p.fg;
|
|
2883
|
+
const head = (0, import_react2.createElement)(
|
|
2884
|
+
RN3.View,
|
|
2885
|
+
{ key: "head", style: { flexDirection: "row", alignItems: "center", gap: 10, paddingLeft: 16, paddingRight: 12, paddingTop: 16, paddingBottom: 12, backgroundColor: onHome ? p.accent : p.bg, borderBottomWidth: onHome ? 0 : 1, borderBottomColor: p.line } },
|
|
2886
|
+
typeof view !== "string" ? (0, import_react2.createElement)(RN3.Pressable, { key: "back", onPress: () => setView("help"), accessibilityRole: "button", hitSlop: 10 }, k.text("\u2039 All articles", { color: p.accent, fontWeight: "600" })) : view === "help" ? null : teamMark(title, onHome ? ink : p.accent, onHome ? p.accent : ink, onHome ? 28 : 36),
|
|
2670
2887
|
(0, import_react2.createElement)(
|
|
2671
2888
|
RN3.View,
|
|
2672
|
-
{
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2889
|
+
{ style: { flex: 1, minWidth: 0 } },
|
|
2890
|
+
typeof view !== "string" ? null : (0, import_react2.createElement)(RN3.Text, { accessibilityRole: "header", numberOfLines: 1, style: { color: headFg, fontSize: 17, fontWeight: "700" } }, view === "help" ? "Help" : title),
|
|
2891
|
+
view === "messages" ? k.muted(reply, { fontSize: 12 }) : null
|
|
2892
|
+
),
|
|
2893
|
+
(0, import_react2.createElement)(RN3.Pressable, { onPress: close, accessibilityRole: "button", accessibilityLabel: "Close", hitSlop: 12, style: { width: 32, height: 32, borderRadius: 10, alignItems: "center", justifyContent: "center" } }, glyph("cross", onHome ? ink : p.muted, 18))
|
|
2894
|
+
);
|
|
2895
|
+
return (0, import_react2.createElement)(
|
|
2896
|
+
RN3.Modal,
|
|
2897
|
+
{ visible: true, animationType: "slide", presentationStyle: "pageSheet", onRequestClose: close },
|
|
2898
|
+
(0, import_react2.createElement)(
|
|
2899
|
+
RN3.KeyboardAvoidingView,
|
|
2900
|
+
{ behavior: RN3.Platform.OS === "ios" ? "padding" : void 0, style: { flex: 1, backgroundColor: p.bg } },
|
|
2901
|
+
head,
|
|
2902
|
+
content,
|
|
2903
|
+
(0, import_react2.createElement)(
|
|
2904
|
+
RN3.View,
|
|
2905
|
+
{ key: "tabs", accessibilityRole: "tablist", style: { flexDirection: "row", borderTopWidth: 1, borderTopColor: p.line, paddingHorizontal: 8, paddingBottom: 22, backgroundColor: p.bg } },
|
|
2906
|
+
tab("home", "Home", "home"),
|
|
2907
|
+
tab("messages", "Messages", "chat", view === "messages" ? 0 : chat.unseen.length),
|
|
2908
|
+
showHelp ? tab("help", "Help", "help") : null
|
|
2909
|
+
)
|
|
2676
2910
|
)
|
|
2677
|
-
|
|
2911
|
+
);
|
|
2678
2912
|
};
|
|
2679
2913
|
var MRRocketMessenger = ({ client, appearance, options: given = {} }) => {
|
|
2680
2914
|
const [look, setLook] = (0, import_react2.useState)(null);
|
|
@@ -2686,7 +2920,19 @@ var MRRocketMessenger = ({ client, appearance, options: given = {} }) => {
|
|
|
2686
2920
|
return () => ctrl.abort();
|
|
2687
2921
|
}, [client]);
|
|
2688
2922
|
const defined = Object.fromEntries(Object.entries(given).filter(([, v]) => v !== void 0));
|
|
2689
|
-
const options = look ? {
|
|
2923
|
+
const options = look ? {
|
|
2924
|
+
title: look.title,
|
|
2925
|
+
greeting: look.greeting,
|
|
2926
|
+
replyTime: look.replyTime,
|
|
2927
|
+
launcher: look.appLauncher ?? false,
|
|
2928
|
+
position: look.position,
|
|
2929
|
+
label: look.label,
|
|
2930
|
+
help: look.help,
|
|
2931
|
+
preview: look.preview,
|
|
2932
|
+
askEmail: look.askEmail,
|
|
2933
|
+
haptics: look.sound,
|
|
2934
|
+
...defined
|
|
2935
|
+
} : given;
|
|
2690
2936
|
const p = usePalette({ theme: appearance?.theme ?? look?.theme, accent: appearance?.accent ?? look?.accent });
|
|
2691
2937
|
const k = kit(p);
|
|
2692
2938
|
const open = messengerOpen.useOpen();
|
|
@@ -2711,6 +2957,9 @@ var MRRocketMessenger = ({ client, appearance, options: given = {} }) => {
|
|
|
2711
2957
|
if (open) setBanner(null);
|
|
2712
2958
|
}, [open]);
|
|
2713
2959
|
const unseen = chat.unseen.length;
|
|
2960
|
+
const ink = inkOn(p.accent);
|
|
2961
|
+
const label = options.label?.trim() ?? "";
|
|
2962
|
+
const side = options.position === "bottom-left" ? { left: 20 } : { right: 20 };
|
|
2714
2963
|
const launcher = options.launcher ? (0, import_react2.createElement)(
|
|
2715
2964
|
RN3.Pressable,
|
|
2716
2965
|
{
|
|
@@ -2718,9 +2967,28 @@ var MRRocketMessenger = ({ client, appearance, options: given = {} }) => {
|
|
|
2718
2967
|
onPress: () => openAt(unseen ? "messages" : "home"),
|
|
2719
2968
|
accessibilityRole: "button",
|
|
2720
2969
|
accessibilityLabel: unseen ? `Open chat, ${unseen} new` : "Open chat",
|
|
2721
|
-
style: {
|
|
2970
|
+
style: {
|
|
2971
|
+
position: "absolute",
|
|
2972
|
+
...side,
|
|
2973
|
+
bottom: 34,
|
|
2974
|
+
height: label ? 50 : 56,
|
|
2975
|
+
minWidth: label ? 0 : 56,
|
|
2976
|
+
paddingHorizontal: label ? 18 : 0,
|
|
2977
|
+
borderRadius: 28,
|
|
2978
|
+
flexDirection: "row",
|
|
2979
|
+
gap: 8,
|
|
2980
|
+
backgroundColor: p.accent,
|
|
2981
|
+
alignItems: "center",
|
|
2982
|
+
justifyContent: "center",
|
|
2983
|
+
shadowColor: p.accent,
|
|
2984
|
+
shadowOpacity: 0.4,
|
|
2985
|
+
shadowRadius: 12,
|
|
2986
|
+
shadowOffset: { width: 0, height: 6 },
|
|
2987
|
+
elevation: 6
|
|
2988
|
+
}
|
|
2722
2989
|
},
|
|
2723
|
-
|
|
2990
|
+
glyph("chat", ink, label ? 20 : 26),
|
|
2991
|
+
label ? k.text(label, { color: ink, fontWeight: "700" }) : null,
|
|
2724
2992
|
unseen ? (0, import_react2.createElement)(RN3.View, { style: { position: "absolute", top: -2, right: -2, minWidth: 20, height: 20, borderRadius: 10, backgroundColor: p.danger, alignItems: "center", justifyContent: "center", borderWidth: 2, borderColor: p.bg } }, k.text(String(Math.min(unseen, 9)), { color: "#fff", fontSize: 11, fontWeight: "700" })) : null
|
|
2725
2993
|
) : null;
|
|
2726
2994
|
const toast = banner ? (0, import_react2.createElement)(
|
|
@@ -2730,10 +2998,15 @@ var MRRocketMessenger = ({ client, appearance, options: given = {} }) => {
|
|
|
2730
2998
|
onPress: () => openAt("messages"),
|
|
2731
2999
|
accessibilityRole: "button",
|
|
2732
3000
|
accessibilityLiveRegion: "polite",
|
|
2733
|
-
style: { position: "absolute", top: 54, left: 16, right: 16, backgroundColor: p.bg, borderRadius:
|
|
3001
|
+
style: { position: "absolute", top: 54, left: 16, right: 16, flexDirection: "row", alignItems: "flex-start", gap: 12, backgroundColor: p.bg, borderRadius: 18, padding: 14, borderWidth: 1, borderColor: p.line, shadowColor: "#000", shadowOpacity: 0.16, shadowRadius: 18, shadowOffset: { width: 0, height: 8 }, elevation: 8 }
|
|
2734
3002
|
},
|
|
2735
|
-
|
|
2736
|
-
(0, import_react2.createElement)(
|
|
3003
|
+
teamMark(options.title ?? "Chat with us", p.accent, ink),
|
|
3004
|
+
(0, import_react2.createElement)(
|
|
3005
|
+
RN3.View,
|
|
3006
|
+
{ style: { flex: 1, gap: 2 } },
|
|
3007
|
+
k.muted(`${whoLabel[banner.from]}${unseen > 1 ? ` \xB7 ${unseen} new` : ""}`, { fontWeight: "600", fontSize: 12 }),
|
|
3008
|
+
(0, import_react2.createElement)(RN3.Text, { numberOfLines: 3, style: { color: p.fg, fontSize: 15 } }, banner.body)
|
|
3009
|
+
)
|
|
2737
3010
|
) : null;
|
|
2738
3011
|
if (!launcher && !toast && !open) return null;
|
|
2739
3012
|
return (0, import_react2.createElement)(
|