@mrrocket/sdk 0.9.0 → 0.10.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.
@@ -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.9.0";
52
+ var SDK_VERSION = "0.10.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);
@@ -2369,6 +2379,35 @@ var buzz = () => {
2369
2379
  }
2370
2380
  };
2371
2381
  var teamOf = (t) => (t?.messages ?? []).filter((m) => m.from !== "visitor");
2382
+ var svg = null;
2383
+ try {
2384
+ svg = require("react-native-svg");
2385
+ } catch {
2386
+ svg = null;
2387
+ }
2388
+ var GLYPH = {
2389
+ 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",
2390
+ 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",
2391
+ 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",
2392
+ send: "M2.5 8h10M8.5 3.5 13 8l-4.5 4.5",
2393
+ up: "M8 13V3M3.5 7.5 8 3l4.5 4.5",
2394
+ next: "M6 3.5 10.5 8 6 12.5",
2395
+ 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",
2396
+ cross: "m4 4 8 8M12 4l-8 8"
2397
+ };
2398
+ var FALLBACK = { chat: "\u{1F4AC}", home: "\u2302", help: "?", send: "\u2192", up: "\u2191", next: "\u203A", search: "\u2315", cross: "\xD7" };
2399
+ var glyph = (name, color, size = 20) => {
2400
+ const Svg = svg?.Svg ?? svg?.default;
2401
+ 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]);
2402
+ 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" }));
2403
+ };
2404
+ var alpha = (hex, a) => /^#[0-9a-f]{6}$/i.test(hex) ? `${hex}${Math.round(a * 255).toString(16).padStart(2, "0")}` : hex;
2405
+ var teamMark = (title, bg, fg, size = 36) => (0, import_react2.createElement)(
2406
+ RN3.View,
2407
+ { style: { width: size, height: size, borderRadius: size / 2, backgroundColor: bg, alignItems: "center", justifyContent: "center" } },
2408
+ (0, import_react2.createElement)(RN3.Text, { style: { color: fg, fontSize: Math.round(size * 0.42), fontWeight: "700" } }, (title.trim()[0] ?? "?").toUpperCase())
2409
+ );
2410
+ var lift = { shadowColor: "#101218", shadowOpacity: 0.07, shadowRadius: 14, shadowOffset: { width: 0, height: 4 }, elevation: 2 };
2372
2411
  var useChat = (client, o, open, view) => {
2373
2412
  const [thread, setThread] = (0, import_react2.useState)(null);
2374
2413
  const [loaded, setLoaded] = (0, import_react2.useState)(false);
@@ -2570,55 +2609,102 @@ var MessengerSheet = ({
2570
2609
  setPending(null);
2571
2610
  }
2572
2611
  };
2612
+ const ink = inkOn(p.accent);
2613
+ const dark = p.bg === DARK.bg;
2614
+ const canvas = dark ? p.bg : p.soft;
2615
+ const raised = dark ? p.soft : p.bg;
2616
+ const title = o.title ?? "Chat with us";
2617
+ const reply = replyLine(o.replyTime);
2573
2618
  const bubble = (m, isPending = false) => {
2574
2619
  const mine = m.from === "visitor";
2575
2620
  return (0, import_react2.createElement)(
2576
2621
  RN3.View,
2577
2622
  { key: m.id, style: { alignSelf: mine ? "flex-end" : "flex-start", maxWidth: "82%", gap: 4 } },
2578
- (0, import_react2.createElement)(RN3.View, { style: { backgroundColor: mine ? p.accent : p.soft, borderRadius: 14, paddingHorizontal: 12, paddingVertical: 8, opacity: isPending ? 0.7 : 1 } }, k.text(m.body, { color: mine ? "#ffffff" : p.fg })),
2623
+ (0, import_react2.createElement)(
2624
+ RN3.View,
2625
+ {
2626
+ style: {
2627
+ backgroundColor: mine ? p.accent : dark ? p.soft : "#eeeff1",
2628
+ borderRadius: 18,
2629
+ borderBottomRightRadius: mine ? 6 : 18,
2630
+ borderBottomLeftRadius: mine ? 18 : 6,
2631
+ paddingHorizontal: 14,
2632
+ paddingVertical: 9,
2633
+ opacity: isPending ? 0.7 : 1
2634
+ }
2635
+ },
2636
+ k.text(m.body, { color: mine ? ink : p.fg })
2637
+ ),
2579
2638
  ...(m.articles ?? []).map(
2580
2639
  (a) => (0, import_react2.createElement)(
2581
2640
  RN3.Pressable,
2582
- { key: a.id, onPress: () => setView({ article: a.id }), accessibilityRole: "link", style: { borderWidth: 1, borderColor: p.line, borderRadius: 10, paddingHorizontal: 10, paddingVertical: 6 } },
2641
+ { key: a.id, onPress: () => setView({ article: a.id }), accessibilityRole: "link", style: { borderWidth: 1, borderColor: p.line, borderRadius: 12, paddingHorizontal: 10, paddingVertical: 7 } },
2583
2642
  k.text(`\u{1F4C4} ${a.title}`, { fontSize: 13 })
2584
2643
  )
2585
2644
  ),
2586
- m.at ? k.muted(`${mine ? "" : `${whoLabel[m.from]} \xB7 `}${isPending ? "Sending\u2026" : timeAgo(m.at)}`, { fontSize: 11, textAlign: mine ? "right" : "left" }) : null
2645
+ 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
2646
  );
2588
2647
  };
2589
2648
  const row = (a) => (0, import_react2.createElement)(
2590
2649
  RN3.Pressable,
2591
- { key: a.id, onPress: () => setView({ article: a.id }), accessibilityRole: "button", style: { flexDirection: "row", alignItems: "center", paddingVertical: 11, paddingHorizontal: 4 } },
2650
+ { key: a.id, onPress: () => setView({ article: a.id }), accessibilityRole: "button", style: { flexDirection: "row", alignItems: "center", gap: 8, paddingVertical: 11, paddingHorizontal: 8 } },
2592
2651
  k.text(a.title, { flex: 1 }),
2593
- k.muted("\u203A", { fontSize: 18 })
2652
+ glyph("next", p.accent, 14)
2594
2653
  );
2595
- const card = (children, style = {}) => (0, import_react2.createElement)(RN3.View, { style: { backgroundColor: p.bg, borderRadius: 12, padding: 12, borderWidth: 1, borderColor: p.line, ...style } }, ...children);
2596
- const search = k.field({ value: query, onChange: setQuery, placeholder: "Search for help", max: 200 });
2654
+ 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);
2655
+ const searchRow = (onPress) => (0, import_react2.createElement)(
2656
+ RN3.Pressable,
2657
+ { key: "s", onPress, accessibilityRole: "search", style: { flexDirection: "row", alignItems: "center", height: 44, borderRadius: 12, paddingHorizontal: 14, backgroundColor: canvas } },
2658
+ k.muted("Search for help", { flex: 1, fontSize: 15 }),
2659
+ glyph("search", p.accent, 16)
2660
+ );
2661
+ const search = k.field({ value: query, onChange: setQuery, placeholder: "Search for help", max: 200, style: { borderWidth: 0, borderRadius: 12, backgroundColor: raised, ...dark ? {} : lift } });
2597
2662
  const last = thread?.messages.at(-1);
2598
2663
  const showHelp = helpOn && arts.any !== false;
2599
2664
  let content;
2600
2665
  if (view === "home")
2601
2666
  content = (0, import_react2.createElement)(
2602
2667
  RN3.ScrollView,
2603
- { key: "home", style: { flex: 1, backgroundColor: p.soft }, contentContainerStyle: { padding: 16, gap: 12 }, keyboardShouldPersistTaps: "handled" },
2604
- (0, import_react2.createElement)(RN3.Text, { style: { color: p.fg, fontSize: 22, fontWeight: "700", paddingVertical: 6 } }, greeting),
2668
+ { key: "home", style: { flex: 1, backgroundColor: canvas }, contentContainerStyle: { paddingBottom: 24 }, keyboardShouldPersistTaps: "handled" },
2669
+ (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
2670
  (0, import_react2.createElement)(
2606
- RN3.Pressable,
2607
- { onPress: () => setView("messages"), accessibilityRole: "button" },
2608
- card([
2609
- k.text(last ? "Recent message" : "Send us a message", { fontWeight: "700" }),
2610
- k.muted(last ? `${last.from === "visitor" ? "You" : whoLabel[last.from]}: ${last.body}` : "We usually answer within a few hours", { marginTop: 2 })
2611
- ])
2612
- ),
2613
- showHelp ? card([(0, import_react2.createElement)(RN3.Pressable, { key: "s", onPress: () => setView("help") }, (0, import_react2.createElement)(RN3.View, { pointerEvents: "none" }, k.muted("\u{1F50D} Search for help", { paddingVertical: 8 }))), ...(arts.list ?? []).slice(0, 4).map(row)]) : null
2671
+ RN3.View,
2672
+ { style: { marginTop: -48, paddingHorizontal: 16, gap: 12 } },
2673
+ last ? (0, import_react2.createElement)(
2674
+ RN3.Pressable,
2675
+ { key: "recent", onPress: () => setView("messages"), accessibilityRole: "button" },
2676
+ card([
2677
+ k.muted("Recent message", { fontSize: 12, fontWeight: "600", marginBottom: 10 }),
2678
+ (0, import_react2.createElement)(
2679
+ RN3.View,
2680
+ { key: "r", style: { flexDirection: "row", alignItems: "center", gap: 12 } },
2681
+ teamMark(title, p.accent, ink),
2682
+ (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 })),
2683
+ 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)
2684
+ )
2685
+ ])
2686
+ ) : null,
2687
+ (0, import_react2.createElement)(
2688
+ RN3.Pressable,
2689
+ { key: "send", onPress: () => setView("messages"), accessibilityRole: "button" },
2690
+ card(
2691
+ [
2692
+ (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)),
2693
+ (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))
2694
+ ],
2695
+ { flexDirection: "row", alignItems: "center", gap: 12 }
2696
+ )
2697
+ ),
2698
+ showHelp ? card([searchRow(() => setView("help")), ...(arts.list ?? []).slice(0, 4).map(row)], { padding: 8, gap: 2 }) : null
2699
+ )
2614
2700
  );
2615
2701
  else if (view === "messages")
2616
2702
  content = (0, import_react2.createElement)(
2617
2703
  RN3.View,
2618
- { key: "messages", style: { flex: 1 } },
2704
+ { key: "messages", style: { flex: 1, backgroundColor: p.bg } },
2619
2705
  (0, import_react2.createElement)(
2620
2706
  RN3.ScrollView,
2621
- { ref: scroll, style: { flex: 1 }, contentContainerStyle: { padding: 16, gap: 10 } },
2707
+ { ref: scroll, style: { flex: 1 }, contentContainerStyle: { padding: 16, gap: 12 } },
2622
2708
  bubble({ id: "greeting", from: "team", body: greeting, at: "" }),
2623
2709
  !chat.loaded ? k.muted("Loading\u2026") : null,
2624
2710
  ...(thread?.messages ?? []).map((m) => bubble(m)),
@@ -2627,14 +2713,24 @@ var MessengerSheet = ({
2627
2713
  ),
2628
2714
  (0, import_react2.createElement)(
2629
2715
  RN3.View,
2630
- { style: { padding: 12, gap: 8, borderTopWidth: 1, borderTopColor: p.line } },
2716
+ { style: { paddingHorizontal: 12, paddingTop: 8, paddingBottom: 10, gap: 8 } },
2631
2717
  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 ? {} : { borderColor: p.danger } }) : null,
2718
+ 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
2719
  (0, import_react2.createElement)(
2634
2720
  RN3.View,
2635
- { style: { flexDirection: "row", gap: 8, alignItems: "flex-end" } },
2636
- k.field({ value: body, onChange: setBody, placeholder: "Write a message\u2026", multiline: true, max: 4e3, style: { flex: 1, minHeight: 44, maxHeight: 120 } }),
2637
- k.btn("Send", "primary", () => void send(), !body.trim() || !!pending || !emailOk)
2721
+ { style: { flexDirection: "row", alignItems: "flex-end", gap: 6, borderWidth: 1, borderColor: p.line, borderRadius: 22, paddingVertical: 5, paddingRight: 5, paddingLeft: 16, backgroundColor: p.bg } },
2722
+ 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" } }),
2723
+ (0, import_react2.createElement)(
2724
+ RN3.Pressable,
2725
+ {
2726
+ onPress: () => void send(),
2727
+ disabled: !body.trim() || !!pending || !emailOk,
2728
+ accessibilityRole: "button",
2729
+ accessibilityLabel: "Send",
2730
+ style: { width: 34, height: 34, borderRadius: 17, alignItems: "center", justifyContent: "center", backgroundColor: !body.trim() || !!pending || !emailOk ? p.line : p.accent }
2731
+ },
2732
+ glyph("up", !body.trim() || !!pending || !emailOk ? p.muted : ink, 18)
2733
+ )
2638
2734
  )
2639
2735
  )
2640
2736
  );
@@ -2643,11 +2739,11 @@ var MessengerSheet = ({
2643
2739
  for (const a of arts.list ?? []) groups.set(a.collection, [...groups.get(a.collection) ?? [], a]);
2644
2740
  content = (0, import_react2.createElement)(
2645
2741
  RN3.ScrollView,
2646
- { key: "help", style: { flex: 1, backgroundColor: p.soft }, contentContainerStyle: { padding: 16, gap: 12 }, keyboardShouldPersistTaps: "handled" },
2742
+ { key: "help", style: { flex: 1, backgroundColor: canvas }, contentContainerStyle: { padding: 16, gap: 12 }, keyboardShouldPersistTaps: "handled" },
2647
2743
  search,
2648
2744
  arts.list === null ? k.muted("Loading\u2026") : null,
2649
2745
  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}`), card(items.map(row))))
2746
+ ...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
2747
  );
2652
2748
  } else
2653
2749
  content = (0, import_react2.createElement)(
@@ -2656,25 +2752,44 @@ var MessengerSheet = ({
2656
2752
  (0, import_react2.createElement)(ArticleView, { client, p, id: view.article, onAsk: () => setView("messages") })
2657
2753
  );
2658
2754
  const current = typeof view === "string" ? view : "help";
2659
- const tab = (v, name, glyph, badge = 0) => (0, import_react2.createElement)(
2755
+ const tab = (v, name, icon, badge = 0) => (0, import_react2.createElement)(
2660
2756
  RN3.Pressable,
2661
- { key: v, onPress: () => setView(v), accessibilityRole: "tab", accessibilityState: { selected: current === v }, style: { flex: 1, alignItems: "center", paddingTop: 8, paddingBottom: 6, gap: 2 } },
2662
- k.text(glyph, { fontSize: 18, color: current === v ? p.fg : p.muted }),
2663
- k.text(name, { fontSize: 12, fontWeight: "600", color: current === v ? p.fg : p.muted }),
2664
- badge ? (0, import_react2.createElement)(RN3.View, { style: { position: "absolute", top: 4, right: "30%", 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
2757
+ { key: v, onPress: () => setView(v), accessibilityRole: "tab", accessibilityState: { selected: current === v }, style: { flex: 1, alignItems: "center", paddingTop: 8, paddingBottom: 6, gap: 3 } },
2758
+ glyph(icon, current === v ? p.accent : p.muted, 22),
2759
+ k.text(name, { fontSize: 12, fontWeight: "600", color: current === v ? p.accent : p.muted }),
2760
+ 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
2761
  );
2666
- const titleOf = typeof view !== "string" || view === "help" ? "Help" : view === "messages" ? o.title ?? "Chat with us" : o.title ?? "Chat with us";
2667
- return k.page(titleOf, close, [
2668
- typeof view !== "string" ? (0, import_react2.createElement)(RN3.Pressable, { key: "back", onPress: () => setView("help"), accessibilityRole: "button", style: { paddingHorizontal: 16, paddingVertical: 8 } }, k.text("\u2039 All articles", { color: p.accent, fontWeight: "600" })) : null,
2669
- content,
2762
+ const onHome = view === "home";
2763
+ const headFg = onHome ? ink : p.fg;
2764
+ const head = (0, import_react2.createElement)(
2765
+ RN3.View,
2766
+ { 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 } },
2767
+ 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
2768
  (0, import_react2.createElement)(
2671
2769
  RN3.View,
2672
- { key: "tabs", accessibilityRole: "tablist", style: { flexDirection: "row", borderTopWidth: 1, borderTopColor: p.line, paddingBottom: 20, backgroundColor: p.bg } },
2673
- tab("home", "Home", "\u2302"),
2674
- tab("messages", "Messages", "\u2709\uFE0E", view === "messages" ? 0 : chat.unseen.length),
2675
- showHelp ? tab("help", "Help", "?") : null
2770
+ { style: { flex: 1, minWidth: 0 } },
2771
+ 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),
2772
+ view === "messages" ? k.muted(reply, { fontSize: 12 }) : null
2773
+ ),
2774
+ (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))
2775
+ );
2776
+ return (0, import_react2.createElement)(
2777
+ RN3.Modal,
2778
+ { visible: true, animationType: "slide", presentationStyle: "pageSheet", onRequestClose: close },
2779
+ (0, import_react2.createElement)(
2780
+ RN3.KeyboardAvoidingView,
2781
+ { behavior: RN3.Platform.OS === "ios" ? "padding" : void 0, style: { flex: 1, backgroundColor: p.bg } },
2782
+ head,
2783
+ content,
2784
+ (0, import_react2.createElement)(
2785
+ RN3.View,
2786
+ { key: "tabs", accessibilityRole: "tablist", style: { flexDirection: "row", borderTopWidth: 1, borderTopColor: p.line, paddingHorizontal: 8, paddingBottom: 22, backgroundColor: p.bg } },
2787
+ tab("home", "Home", "home"),
2788
+ tab("messages", "Messages", "chat", view === "messages" ? 0 : chat.unseen.length),
2789
+ showHelp ? tab("help", "Help", "help") : null
2790
+ )
2676
2791
  )
2677
- ]);
2792
+ );
2678
2793
  };
2679
2794
  var MRRocketMessenger = ({ client, appearance, options: given = {} }) => {
2680
2795
  const [look, setLook] = (0, import_react2.useState)(null);
@@ -2686,7 +2801,19 @@ var MRRocketMessenger = ({ client, appearance, options: given = {} }) => {
2686
2801
  return () => ctrl.abort();
2687
2802
  }, [client]);
2688
2803
  const defined = Object.fromEntries(Object.entries(given).filter(([, v]) => v !== void 0));
2689
- const options = look ? { title: look.title, greeting: look.greeting, help: look.help, preview: look.preview, askEmail: look.askEmail, ...defined } : given;
2804
+ const options = look ? {
2805
+ title: look.title,
2806
+ greeting: look.greeting,
2807
+ replyTime: look.replyTime,
2808
+ launcher: look.appLauncher ?? false,
2809
+ position: look.position,
2810
+ label: look.label,
2811
+ help: look.help,
2812
+ preview: look.preview,
2813
+ askEmail: look.askEmail,
2814
+ haptics: look.sound,
2815
+ ...defined
2816
+ } : given;
2690
2817
  const p = usePalette({ theme: appearance?.theme ?? look?.theme, accent: appearance?.accent ?? look?.accent });
2691
2818
  const k = kit(p);
2692
2819
  const open = messengerOpen.useOpen();
@@ -2711,6 +2838,9 @@ var MRRocketMessenger = ({ client, appearance, options: given = {} }) => {
2711
2838
  if (open) setBanner(null);
2712
2839
  }, [open]);
2713
2840
  const unseen = chat.unseen.length;
2841
+ const ink = inkOn(p.accent);
2842
+ const label = options.label?.trim() ?? "";
2843
+ const side = options.position === "bottom-left" ? { left: 20 } : { right: 20 };
2714
2844
  const launcher = options.launcher ? (0, import_react2.createElement)(
2715
2845
  RN3.Pressable,
2716
2846
  {
@@ -2718,9 +2848,28 @@ var MRRocketMessenger = ({ client, appearance, options: given = {} }) => {
2718
2848
  onPress: () => openAt(unseen ? "messages" : "home"),
2719
2849
  accessibilityRole: "button",
2720
2850
  accessibilityLabel: unseen ? `Open chat, ${unseen} new` : "Open chat",
2721
- style: { position: "absolute", right: 20, bottom: 34, width: 54, height: 54, borderRadius: 27, backgroundColor: p.accent, alignItems: "center", justifyContent: "center", shadowColor: "#000", shadowOpacity: 0.2, shadowRadius: 10, elevation: 6 }
2851
+ style: {
2852
+ position: "absolute",
2853
+ ...side,
2854
+ bottom: 34,
2855
+ height: label ? 50 : 56,
2856
+ minWidth: label ? 0 : 56,
2857
+ paddingHorizontal: label ? 18 : 0,
2858
+ borderRadius: 28,
2859
+ flexDirection: "row",
2860
+ gap: 8,
2861
+ backgroundColor: p.accent,
2862
+ alignItems: "center",
2863
+ justifyContent: "center",
2864
+ shadowColor: p.accent,
2865
+ shadowOpacity: 0.4,
2866
+ shadowRadius: 12,
2867
+ shadowOffset: { width: 0, height: 6 },
2868
+ elevation: 6
2869
+ }
2722
2870
  },
2723
- k.text("\u{1F4AC}", { fontSize: 22 }),
2871
+ glyph("chat", ink, label ? 20 : 26),
2872
+ label ? k.text(label, { color: ink, fontWeight: "700" }) : null,
2724
2873
  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
2874
  ) : null;
2726
2875
  const toast = banner ? (0, import_react2.createElement)(
@@ -2730,10 +2879,15 @@ var MRRocketMessenger = ({ client, appearance, options: given = {} }) => {
2730
2879
  onPress: () => openAt("messages"),
2731
2880
  accessibilityRole: "button",
2732
2881
  accessibilityLiveRegion: "polite",
2733
- style: { position: "absolute", top: 54, left: 16, right: 16, backgroundColor: p.bg, borderRadius: 14, padding: 14, gap: 2, borderWidth: 1, borderColor: p.line, shadowColor: "#000", shadowOpacity: 0.18, shadowRadius: 16, elevation: 8 }
2882
+ 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
2883
  },
2735
- k.muted(`${whoLabel[banner.from]}${unseen > 1 ? ` \xB7 ${unseen} new` : ""}`, { fontWeight: "600", fontSize: 12 }),
2736
- (0, import_react2.createElement)(RN3.Text, { numberOfLines: 3, style: { color: p.fg, fontSize: 15 } }, banner.body)
2884
+ teamMark(options.title ?? "Chat with us", p.accent, ink),
2885
+ (0, import_react2.createElement)(
2886
+ RN3.View,
2887
+ { style: { flex: 1, gap: 2 } },
2888
+ k.muted(`${whoLabel[banner.from]}${unseen > 1 ? ` \xB7 ${unseen} new` : ""}`, { fontWeight: "600", fontSize: 12 }),
2889
+ (0, import_react2.createElement)(RN3.Text, { numberOfLines: 3, style: { color: p.fg, fontSize: 15 } }, banner.body)
2890
+ )
2737
2891
  ) : null;
2738
2892
  if (!launcher && !toast && !open) return null;
2739
2893
  return (0, import_react2.createElement)(