@mushi-mushi/react-native 0.15.1 → 0.16.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/README.md +1 -1
- package/dist/index.cjs +268 -125
- package/dist/index.d.cts +20 -20
- package/dist/index.d.ts +20 -20
- package/dist/index.js +279 -134
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -120,4 +120,4 @@ MIT
|
|
|
120
120
|
<!-- mushi-readme-stats-footer -->
|
|
121
121
|
---
|
|
122
122
|
|
|
123
|
-
<sub>Monorepo scale (June 2026):
|
|
123
|
+
<sub>Monorepo scale (June 2026): 47 edge functions · 256 SQL migrations · 13 outbound plugins · 11 inbound adapters · 18 pipeline agents. Canonical counts: <a href="https://github.com/kensaurus/mushi-mushi/blob/master/docs/stats.md">docs/stats.md</a> · <code>pnpm docs-stats</code></sub>
|
package/dist/index.cjs
CHANGED
|
@@ -328,6 +328,7 @@ var CATEGORIES = [
|
|
|
328
328
|
{ key: "confusing", emoji: "\u{1F615}", label: "Confusing" },
|
|
329
329
|
{ key: "other", emoji: "\u{1F4AC}", label: "Other" }
|
|
330
330
|
];
|
|
331
|
+
var VERIFIABLE_STATUSES = /* @__PURE__ */ new Set(["fixed", "resolved", "verified"]);
|
|
331
332
|
var MushiBottomSheet = ({
|
|
332
333
|
visible,
|
|
333
334
|
onClose,
|
|
@@ -349,12 +350,6 @@ var MushiBottomSheet = ({
|
|
|
349
350
|
const [threadComments, setThreadComments] = (0, import_react.useState)([]);
|
|
350
351
|
const [replyText, setReplyText] = (0, import_react.useState)("");
|
|
351
352
|
const [screenshotAttached, setScreenshotAttached] = (0, import_react.useState)(true);
|
|
352
|
-
(0, import_react.useEffect)(() => {
|
|
353
|
-
if (visible) {
|
|
354
|
-
setScreenshotAttached(true);
|
|
355
|
-
if (sheetTab === "inbox") void loadInbox();
|
|
356
|
-
}
|
|
357
|
-
}, [visible, sheetTab]);
|
|
358
353
|
const loadInbox = (0, import_react.useCallback)(async () => {
|
|
359
354
|
if (!mushi?.listMyReports) return;
|
|
360
355
|
setInboxLoading(true);
|
|
@@ -365,6 +360,12 @@ var MushiBottomSheet = ({
|
|
|
365
360
|
setInboxLoading(false);
|
|
366
361
|
}
|
|
367
362
|
}, [mushi]);
|
|
363
|
+
(0, import_react.useEffect)(() => {
|
|
364
|
+
if (visible) {
|
|
365
|
+
setScreenshotAttached(true);
|
|
366
|
+
if (sheetTab === "inbox") void loadInbox();
|
|
367
|
+
}
|
|
368
|
+
}, [visible, sheetTab, loadInbox]);
|
|
368
369
|
const openThread = (0, import_react.useCallback)(async (reportId) => {
|
|
369
370
|
setSelectedReportId(reportId);
|
|
370
371
|
if (!mushi?.listMyComments) return;
|
|
@@ -466,13 +467,14 @@ var MushiBottomSheet = ({
|
|
|
466
467
|
}
|
|
467
468
|
};
|
|
468
469
|
const activeScreenshot = screenshotDataUrl && screenshotAttached ? screenshotDataUrl : null;
|
|
469
|
-
const colors = dark ? { bg: "#1c1c1e", text: "#f2f2f7", sub: "#8e8e93", card: "#2c2c2e", accent: "#0a84ff", border: "#38383a", backdrop: "rgba(0,0,0,0.6)" } : { bg: "#ffffff", text: "#1c1c1e", sub: "#8e8e93", card: "#f2f2f7", accent: "#007aff", border: "#e5e5ea", backdrop: "rgba(0,0,0,0.35)" };
|
|
470
|
+
const colors = dark ? { bg: "#1c1c1e", text: "#f2f2f7", sub: "#8e8e93", card: "#2c2c2e", accent: "#0a84ff", border: "#38383a", backdrop: "rgba(0,0,0,0.6)", disabled: "#3a3a3c", disabledText: "#636366" } : { bg: "#ffffff", text: "#1c1c1e", sub: "#8e8e93", card: "#f2f2f7", accent: "#007aff", border: "#e5e5ea", backdrop: "rgba(0,0,0,0.35)", disabled: "#d1d1d6", disabledText: "#8e8e93" };
|
|
470
471
|
const canSubmit = !!category && description.trim().length > 0 && phase === "form";
|
|
471
472
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Modal, { visible, transparent: true, animationType: "none", statusBarTranslucent: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
472
473
|
import_react_native2.KeyboardAvoidingView,
|
|
473
474
|
{
|
|
474
475
|
style: s.flex,
|
|
475
|
-
behavior: import_react_native2.Platform.OS === "ios" ? "padding" :
|
|
476
|
+
behavior: import_react_native2.Platform.OS === "ios" ? "padding" : "height",
|
|
477
|
+
keyboardVerticalOffset: import_react_native2.Platform.OS === "ios" ? 0 : 20,
|
|
476
478
|
children: [
|
|
477
479
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
478
480
|
import_react_native2.Animated.View,
|
|
@@ -490,7 +492,7 @@ var MushiBottomSheet = ({
|
|
|
490
492
|
],
|
|
491
493
|
children: [
|
|
492
494
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { ...panResponder.panHandlers, style: s.handleArea, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: [s.handle, { backgroundColor: colors.sub }] }) }),
|
|
493
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: s.tabRow, children: ["report", "inbox"].map((tab) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
495
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: s.tabRow, children: ["report", "inbox", "community"].map((tab) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
494
496
|
import_react_native2.TouchableOpacity,
|
|
495
497
|
{
|
|
496
498
|
onPress: () => {
|
|
@@ -499,17 +501,19 @@ var MushiBottomSheet = ({
|
|
|
499
501
|
else setSelectedReportId(null);
|
|
500
502
|
},
|
|
501
503
|
style: [s.tabBtn, sheetTab === tab && { borderBottomColor: colors.accent }],
|
|
502
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.tabLabel, { color: sheetTab === tab ? colors.accent : colors.sub }], children: tab === "report" ? "Report" : "Inbox" })
|
|
504
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.tabLabel, { color: sheetTab === tab ? colors.accent : colors.sub }], children: tab === "report" ? "Report" : tab === "inbox" ? "Inbox" : "\u{1F310}" })
|
|
503
505
|
},
|
|
504
506
|
tab
|
|
505
507
|
)) }),
|
|
506
|
-
sheetTab === "inbox" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.
|
|
508
|
+
sheetTab === "inbox" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.ScrollView, { style: s.body, keyboardShouldPersistTaps: "handled", children: inboxLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: { color: colors.sub }, children: "Loading\u2026" }) : selectedReportId ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
507
509
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.TouchableOpacity, { onPress: () => setSelectedReportId(null), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: { color: colors.accent, marginBottom: 8 }, children: "\u2190 Back" }) }),
|
|
508
510
|
threadComments.map((c) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: [s.threadBubble, { backgroundColor: colors.card }], children: [
|
|
509
511
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: { color: colors.sub, fontSize: 11 }, children: c.author_kind }),
|
|
510
512
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: { color: colors.text }, children: c.body })
|
|
511
513
|
] }, c.id)),
|
|
512
|
-
|
|
514
|
+
VERIFIABLE_STATUSES.has(
|
|
515
|
+
inboxReports.find((r) => r.id === selectedReportId)?.status ?? ""
|
|
516
|
+
) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: s.verifyRow, children: [
|
|
513
517
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.TouchableOpacity, { style: [s.verifyBtn, { backgroundColor: colors.accent }], onPress: () => submitFeedback("confirms"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: s.submitText, children: "Yes, fixed" }) }),
|
|
514
518
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.TouchableOpacity, { style: [s.verifyBtn, { backgroundColor: colors.border }], onPress: () => submitFeedback("not_fixed"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.submitText, { color: colors.text }], children: "Not fixed" }) })
|
|
515
519
|
] }),
|
|
@@ -527,102 +531,127 @@ var MushiBottomSheet = ({
|
|
|
527
531
|
] }) : inboxReports.map((r) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.TouchableOpacity, { style: [s.inboxRow, { borderColor: colors.border }], onPress: () => openThread(r.id), children: [
|
|
528
532
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: { color: colors.text, fontWeight: "600" }, numberOfLines: 1, children: (r.summary ?? r.description ?? "Report").slice(0, 60) }),
|
|
529
533
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: { color: colors.sub, fontSize: 11 }, children: r.status })
|
|
530
|
-
] }, r.id)) }) :
|
|
534
|
+
] }, r.id)) }) : sheetTab === "community" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.ScrollView, { style: s.body, keyboardShouldPersistTaps: "handled", children: [
|
|
535
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.title, { color: colors.text }], children: "\u{1F310} Mushi Community" }),
|
|
536
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: { color: colors.sub, fontSize: 13, marginBottom: 16, lineHeight: 18 }, children: "Sign in to track your reports across apps and see the global leaderboard. No password needed." }),
|
|
537
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
538
|
+
import_react_native2.TextInput,
|
|
539
|
+
{
|
|
540
|
+
style: [s.input, { backgroundColor: colors.card, color: colors.text, borderColor: colors.border, minHeight: 48 }],
|
|
541
|
+
placeholder: "you@example.com",
|
|
542
|
+
placeholderTextColor: colors.sub,
|
|
543
|
+
keyboardType: "email-address",
|
|
544
|
+
autoCapitalize: "none",
|
|
545
|
+
autoCorrect: false,
|
|
546
|
+
textContentType: "emailAddress"
|
|
547
|
+
}
|
|
548
|
+
),
|
|
549
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.TouchableOpacity, { style: [s.submitBtn, { backgroundColor: colors.accent }], children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: s.submitText, children: "Send sign-in link \u2192" }) }),
|
|
550
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: { color: colors.sub, fontSize: 11, textAlign: "center", marginTop: 12 }, children: "We'll email you a one-tap sign-in link. No password, ever." })
|
|
551
|
+
] }) : phase === "sent" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: s.sentWrap, children: [
|
|
531
552
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.sentEmoji], children: "\u2705" }),
|
|
532
553
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.sentText, { color: colors.text }], children: "Report sent!" })
|
|
533
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
554
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
555
|
+
import_react_native2.ScrollView,
|
|
556
|
+
{
|
|
557
|
+
style: s.body,
|
|
558
|
+
keyboardShouldPersistTaps: "handled",
|
|
559
|
+
contentContainerStyle: { paddingBottom: 24 },
|
|
560
|
+
children: [
|
|
561
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.title, { color: colors.text }], children: "Report an issue" }),
|
|
562
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: s.catRow, children: CATEGORIES.map((c) => {
|
|
563
|
+
const active = category === c.key;
|
|
564
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
565
|
+
import_react_native2.TouchableOpacity,
|
|
544
566
|
{
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
567
|
+
onPress: () => setCategory(c.key),
|
|
568
|
+
activeOpacity: 0.7,
|
|
569
|
+
style: [
|
|
570
|
+
s.catBtn,
|
|
571
|
+
{
|
|
572
|
+
backgroundColor: active ? colors.accent : colors.card,
|
|
573
|
+
borderColor: active ? colors.accent : colors.border
|
|
574
|
+
}
|
|
575
|
+
],
|
|
576
|
+
children: [
|
|
577
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: s.catEmoji, children: c.emoji }),
|
|
578
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
579
|
+
import_react_native2.Text,
|
|
580
|
+
{
|
|
581
|
+
style: [
|
|
582
|
+
s.catLabel,
|
|
583
|
+
{ color: active ? "#fff" : colors.text }
|
|
584
|
+
],
|
|
585
|
+
children: c.label
|
|
586
|
+
}
|
|
587
|
+
)
|
|
588
|
+
]
|
|
589
|
+
},
|
|
590
|
+
c.key
|
|
591
|
+
);
|
|
592
|
+
}) }),
|
|
593
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
594
|
+
import_react_native2.TextInput,
|
|
595
|
+
{
|
|
596
|
+
style: [
|
|
597
|
+
s.input,
|
|
553
598
|
{
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
],
|
|
558
|
-
children: c.label
|
|
599
|
+
backgroundColor: colors.card,
|
|
600
|
+
color: colors.text,
|
|
601
|
+
borderColor: colors.border
|
|
559
602
|
}
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
603
|
+
],
|
|
604
|
+
placeholder: "What happened?",
|
|
605
|
+
placeholderTextColor: colors.sub,
|
|
606
|
+
multiline: true,
|
|
607
|
+
textAlignVertical: "top",
|
|
608
|
+
value: description,
|
|
609
|
+
onChangeText: setDescription,
|
|
610
|
+
editable: phase === "form"
|
|
611
|
+
}
|
|
612
|
+
),
|
|
613
|
+
activeScreenshot ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: s.screenshotRow, children: [
|
|
614
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
615
|
+
import_react_native2.Image,
|
|
616
|
+
{
|
|
617
|
+
source: { uri: activeScreenshot },
|
|
618
|
+
style: s.screenshotThumb,
|
|
619
|
+
accessibilityLabel: "Attached screenshot"
|
|
620
|
+
}
|
|
621
|
+
),
|
|
622
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: s.screenshotMeta, children: [
|
|
623
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.screenshotLabel, { color: colors.text }], children: "Screenshot attached" }),
|
|
624
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.screenshotSub, { color: colors.sub }], children: "Helps the team see the issue" })
|
|
625
|
+
] }),
|
|
626
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
627
|
+
import_react_native2.TouchableOpacity,
|
|
628
|
+
{
|
|
629
|
+
onPress: () => {
|
|
630
|
+
setScreenshotAttached(false);
|
|
631
|
+
onClearScreenshot?.();
|
|
632
|
+
},
|
|
633
|
+
hitSlop: { top: 8, bottom: 8, left: 8, right: 8 },
|
|
634
|
+
accessibilityLabel: "Remove screenshot",
|
|
635
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.screenshotRemove, { color: colors.sub }], children: "\u2715" })
|
|
636
|
+
}
|
|
637
|
+
)
|
|
638
|
+
] }) : null,
|
|
639
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
640
|
+
import_react_native2.TouchableOpacity,
|
|
571
641
|
{
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
642
|
+
onPress: handleSubmit,
|
|
643
|
+
disabled: !canSubmit,
|
|
644
|
+
activeOpacity: 0.8,
|
|
645
|
+
style: [
|
|
646
|
+
s.submitBtn,
|
|
647
|
+
{ backgroundColor: canSubmit ? colors.accent : colors.disabled }
|
|
648
|
+
],
|
|
649
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.submitText, !canSubmit && { color: colors.disabledText }], children: phase === "sending" ? "Sending\u2026" : "Submit" })
|
|
575
650
|
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
textAlignVertical: "top",
|
|
581
|
-
value: description,
|
|
582
|
-
onChangeText: setDescription,
|
|
583
|
-
editable: phase === "form"
|
|
584
|
-
}
|
|
585
|
-
),
|
|
586
|
-
activeScreenshot ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: s.screenshotRow, children: [
|
|
587
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
588
|
-
import_react_native2.Image,
|
|
589
|
-
{
|
|
590
|
-
source: { uri: activeScreenshot },
|
|
591
|
-
style: s.screenshotThumb,
|
|
592
|
-
accessibilityLabel: "Attached screenshot"
|
|
593
|
-
}
|
|
594
|
-
),
|
|
595
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: s.screenshotMeta, children: [
|
|
596
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.screenshotLabel, { color: colors.text }], children: "Screenshot attached" }),
|
|
597
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.screenshotSub, { color: colors.sub }], children: "Helps the team see the issue" })
|
|
598
|
-
] }),
|
|
599
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
600
|
-
import_react_native2.TouchableOpacity,
|
|
601
|
-
{
|
|
602
|
-
onPress: () => {
|
|
603
|
-
setScreenshotAttached(false);
|
|
604
|
-
onClearScreenshot?.();
|
|
605
|
-
},
|
|
606
|
-
hitSlop: { top: 8, bottom: 8, left: 8, right: 8 },
|
|
607
|
-
accessibilityLabel: "Remove screenshot",
|
|
608
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.screenshotRemove, { color: colors.sub }], children: "\u2715" })
|
|
609
|
-
}
|
|
610
|
-
)
|
|
611
|
-
] }) : null,
|
|
612
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
613
|
-
import_react_native2.TouchableOpacity,
|
|
614
|
-
{
|
|
615
|
-
onPress: handleSubmit,
|
|
616
|
-
disabled: !canSubmit,
|
|
617
|
-
activeOpacity: 0.8,
|
|
618
|
-
style: [
|
|
619
|
-
s.submitBtn,
|
|
620
|
-
{ backgroundColor: canSubmit ? colors.accent : colors.border }
|
|
621
|
-
],
|
|
622
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: s.submitText, children: phase === "sending" ? "Sending\u2026" : "Submit" })
|
|
623
|
-
}
|
|
624
|
-
)
|
|
625
|
-
] })
|
|
651
|
+
)
|
|
652
|
+
]
|
|
653
|
+
}
|
|
654
|
+
)
|
|
626
655
|
]
|
|
627
656
|
}
|
|
628
657
|
)
|
|
@@ -798,15 +827,133 @@ var s = import_react_native2.StyleSheet.create({
|
|
|
798
827
|
var import_react2 = require("react");
|
|
799
828
|
var import_react_native3 = require("react-native");
|
|
800
829
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
830
|
+
var FAB_SIZE = 56;
|
|
831
|
+
var EDGE_PADDING = 12;
|
|
832
|
+
function getScreenBounds() {
|
|
833
|
+
const { width, height } = import_react_native3.Dimensions.get("window");
|
|
834
|
+
return { width, height };
|
|
835
|
+
}
|
|
836
|
+
function clamp(value, min, max) {
|
|
837
|
+
return Math.min(Math.max(value, min), max);
|
|
838
|
+
}
|
|
839
|
+
var STORAGE_KEY = "mushi:fab-pos";
|
|
840
|
+
async function loadStoredPos() {
|
|
841
|
+
try {
|
|
842
|
+
const AsyncStorage = (await import("@react-native-async-storage/async-storage")).default;
|
|
843
|
+
const raw = await AsyncStorage.getItem(STORAGE_KEY);
|
|
844
|
+
if (!raw) return null;
|
|
845
|
+
return JSON.parse(raw);
|
|
846
|
+
} catch {
|
|
847
|
+
return null;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
async function storePos(pos) {
|
|
851
|
+
try {
|
|
852
|
+
const AsyncStorage = (await import("@react-native-async-storage/async-storage")).default;
|
|
853
|
+
await AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(pos));
|
|
854
|
+
} catch {
|
|
855
|
+
}
|
|
856
|
+
}
|
|
801
857
|
var MushiFloatingButton = ({
|
|
802
858
|
onPress,
|
|
803
859
|
position = "bottom-right",
|
|
804
|
-
inset
|
|
860
|
+
inset,
|
|
861
|
+
config,
|
|
862
|
+
accent
|
|
805
863
|
}) => {
|
|
806
864
|
const scheme = (0, import_react_native3.useColorScheme)();
|
|
807
865
|
const dark = scheme === "dark";
|
|
866
|
+
const draggable = config?.draggable ?? false;
|
|
867
|
+
const snapToEdge = config?.snapToEdge ?? true;
|
|
868
|
+
const persist = config?.persist ?? false;
|
|
869
|
+
const baseBottom = inset?.bottom ?? (import_react_native3.Platform.OS === "ios" ? 50 : 28);
|
|
870
|
+
const baseX = position === "bottom-left" ? inset?.left ?? EDGE_PADDING : (() => {
|
|
871
|
+
const { width } = getScreenBounds();
|
|
872
|
+
return width - FAB_SIZE - (inset?.right ?? EDGE_PADDING);
|
|
873
|
+
})();
|
|
808
874
|
const scale = (0, import_react2.useRef)(new import_react_native3.Animated.Value(1)).current;
|
|
875
|
+
const posX = (0, import_react2.useRef)(new import_react_native3.Animated.Value(baseX)).current;
|
|
876
|
+
const posY = (0, import_react2.useRef)(new import_react_native3.Animated.Value(0)).current;
|
|
877
|
+
const currentX = (0, import_react2.useRef)(baseX);
|
|
878
|
+
const currentY = (0, import_react2.useRef)(0);
|
|
879
|
+
const isDragging = (0, import_react2.useRef)(false);
|
|
880
|
+
const accentColor = accent ?? (dark ? "#0a84ff" : "#007aff");
|
|
881
|
+
(0, import_react2.useEffect)(() => {
|
|
882
|
+
if (!persist) return;
|
|
883
|
+
void loadStoredPos().then((pos) => {
|
|
884
|
+
if (!pos) return;
|
|
885
|
+
currentX.current = pos.x;
|
|
886
|
+
currentY.current = pos.y;
|
|
887
|
+
posX.setValue(pos.x);
|
|
888
|
+
posY.setValue(pos.y);
|
|
889
|
+
});
|
|
890
|
+
}, [persist, posX, posY]);
|
|
891
|
+
const snapAndPersist = (0, import_react2.useCallback)(
|
|
892
|
+
(x, y) => {
|
|
893
|
+
const { width, height } = getScreenBounds();
|
|
894
|
+
let snappedX = x;
|
|
895
|
+
if (snapToEdge) {
|
|
896
|
+
const midX = width / 2;
|
|
897
|
+
snappedX = x + FAB_SIZE / 2 < midX ? EDGE_PADDING : width - FAB_SIZE - EDGE_PADDING;
|
|
898
|
+
}
|
|
899
|
+
const clampedX = clamp(snappedX, EDGE_PADDING, width - FAB_SIZE - EDGE_PADDING);
|
|
900
|
+
const clampedY = clamp(y, -(height - FAB_SIZE - baseBottom - 60), 0);
|
|
901
|
+
currentX.current = clampedX;
|
|
902
|
+
currentY.current = clampedY;
|
|
903
|
+
import_react_native3.Animated.spring(posX, {
|
|
904
|
+
toValue: clampedX,
|
|
905
|
+
useNativeDriver: false,
|
|
906
|
+
damping: 18,
|
|
907
|
+
stiffness: 220
|
|
908
|
+
}).start();
|
|
909
|
+
import_react_native3.Animated.spring(posY, {
|
|
910
|
+
toValue: clampedY,
|
|
911
|
+
useNativeDriver: false,
|
|
912
|
+
damping: 18,
|
|
913
|
+
stiffness: 220
|
|
914
|
+
}).start();
|
|
915
|
+
if (persist) void storePos({ x: clampedX, y: clampedY });
|
|
916
|
+
},
|
|
917
|
+
[snapToEdge, persist, posX, posY, baseBottom]
|
|
918
|
+
);
|
|
919
|
+
const panResponder = (0, import_react2.useRef)(
|
|
920
|
+
draggable ? import_react_native3.PanResponder.create({
|
|
921
|
+
onStartShouldSetPanResponder: () => true,
|
|
922
|
+
onMoveShouldSetPanResponder: (_, g) => Math.abs(g.dx) > 6 || Math.abs(g.dy) > 6,
|
|
923
|
+
onPanResponderGrant: () => {
|
|
924
|
+
isDragging.current = false;
|
|
925
|
+
posX.stopAnimation();
|
|
926
|
+
posY.stopAnimation();
|
|
927
|
+
},
|
|
928
|
+
onPanResponderMove: (_, g) => {
|
|
929
|
+
if (Math.abs(g.dx) > 6 || Math.abs(g.dy) > 6) {
|
|
930
|
+
isDragging.current = true;
|
|
931
|
+
scale.setValue(1);
|
|
932
|
+
}
|
|
933
|
+
const { width, height } = getScreenBounds();
|
|
934
|
+
const newX = clamp(
|
|
935
|
+
currentX.current + g.dx,
|
|
936
|
+
EDGE_PADDING,
|
|
937
|
+
width - FAB_SIZE - EDGE_PADDING
|
|
938
|
+
);
|
|
939
|
+
const newY = clamp(
|
|
940
|
+
currentY.current + g.dy,
|
|
941
|
+
-(height - FAB_SIZE - baseBottom - 60),
|
|
942
|
+
0
|
|
943
|
+
);
|
|
944
|
+
posX.setValue(newX);
|
|
945
|
+
posY.setValue(newY);
|
|
946
|
+
},
|
|
947
|
+
onPanResponderRelease: (_, g) => {
|
|
948
|
+
if (isDragging.current) {
|
|
949
|
+
snapAndPersist(currentX.current + g.dx, currentY.current + g.dy);
|
|
950
|
+
}
|
|
951
|
+
isDragging.current = false;
|
|
952
|
+
}
|
|
953
|
+
}) : import_react_native3.PanResponder.create({})
|
|
954
|
+
).current;
|
|
809
955
|
const handlePressIn = (0, import_react2.useCallback)(() => {
|
|
956
|
+
if (isDragging.current) return;
|
|
810
957
|
import_react_native3.Animated.spring(scale, {
|
|
811
958
|
toValue: 0.85,
|
|
812
959
|
useNativeDriver: true,
|
|
@@ -821,39 +968,35 @@ var MushiFloatingButton = ({
|
|
|
821
968
|
damping: 10,
|
|
822
969
|
stiffness: 250
|
|
823
970
|
}).start();
|
|
824
|
-
|
|
825
|
-
|
|
971
|
+
if (!isDragging.current) onPress();
|
|
972
|
+
}, [scale, onPress]);
|
|
826
973
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
827
|
-
import_react_native3.
|
|
974
|
+
import_react_native3.Animated.View,
|
|
828
975
|
{
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
833
|
-
import_react_native3.Animated.View,
|
|
976
|
+
...draggable ? panResponder.panHandlers : {},
|
|
977
|
+
style: [
|
|
978
|
+
s2.fab,
|
|
834
979
|
{
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
backgroundColor: dark ? "#0a84ff" : "#007aff",
|
|
841
|
-
transform: [{ scale }],
|
|
842
|
-
shadowColor: dark ? "#0a84ff" : "#000"
|
|
843
|
-
}
|
|
844
|
-
],
|
|
845
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Animated.Text, { style: s2.emoji, children: "\u{1F41B}" })
|
|
980
|
+
left: posX,
|
|
981
|
+
bottom: import_react_native3.Animated.add(new import_react_native3.Animated.Value(baseBottom), import_react_native3.Animated.multiply(posY, -1)),
|
|
982
|
+
backgroundColor: accentColor,
|
|
983
|
+
shadowColor: dark ? accentColor : "#000",
|
|
984
|
+
transform: [{ scale }]
|
|
846
985
|
}
|
|
847
|
-
|
|
986
|
+
],
|
|
987
|
+
onStartShouldSetResponder: () => !draggable,
|
|
988
|
+
onResponderGrant: handlePressIn,
|
|
989
|
+
onResponderRelease: handlePressOut,
|
|
990
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Animated.Text, { style: s2.emoji, children: "\u{1F41B}" })
|
|
848
991
|
}
|
|
849
992
|
);
|
|
850
993
|
};
|
|
851
994
|
var s2 = import_react_native3.StyleSheet.create({
|
|
852
995
|
fab: {
|
|
853
996
|
position: "absolute",
|
|
854
|
-
width:
|
|
855
|
-
height:
|
|
856
|
-
borderRadius:
|
|
997
|
+
width: FAB_SIZE,
|
|
998
|
+
height: FAB_SIZE,
|
|
999
|
+
borderRadius: FAB_SIZE / 2,
|
|
857
1000
|
alignItems: "center",
|
|
858
1001
|
justifyContent: "center",
|
|
859
1002
|
zIndex: 9999,
|
package/dist/index.d.cts
CHANGED
|
@@ -188,29 +188,25 @@ interface MushiBottomSheetProps {
|
|
|
188
188
|
declare const MushiBottomSheet: FC<MushiBottomSheetProps>;
|
|
189
189
|
|
|
190
190
|
/**
|
|
191
|
-
*
|
|
192
|
-
* PURPOSE: Floating action button (FAB) that triggers the Mushi bug-report bottom sheet
|
|
191
|
+
* MushiFloatingButton — draggable, repositionable FAB for the Mushi SDK.
|
|
193
192
|
*
|
|
194
|
-
*
|
|
195
|
-
* -
|
|
196
|
-
* -
|
|
197
|
-
* -
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
* -
|
|
201
|
-
*
|
|
202
|
-
* USAGE:
|
|
203
|
-
* - Rendered automatically by MushiProvider when widget.trigger is 'button' or 'both'
|
|
204
|
-
* - Can be used standalone: <MushiFloatingButton onPress={…} />
|
|
205
|
-
*
|
|
206
|
-
* TECHNICAL DETAILS:
|
|
207
|
-
* - Uses Animated.Value for scale, driven by onPressIn / onPressOut
|
|
208
|
-
* - Safe-area aware: extra bottom padding on iOS
|
|
209
|
-
*
|
|
210
|
-
* NOTES:
|
|
211
|
-
* - Keeps zIndex high (9999) so it floats above app content
|
|
193
|
+
* Supports:
|
|
194
|
+
* - PanResponder drag with tap-vs-drag threshold (6 px)
|
|
195
|
+
* - Clamp to screen bounds with safe-area respect
|
|
196
|
+
* - Optional edge-snap on release (`snapToEdge`)
|
|
197
|
+
* - Persist position to AsyncStorage (opt-in via `persist` config)
|
|
198
|
+
* - Press-in / press-out spring scale animation
|
|
199
|
+
* - Dark/light adaptive colours
|
|
212
200
|
*/
|
|
213
201
|
|
|
202
|
+
interface MushiFloatingButtonConfig {
|
|
203
|
+
/** Allow the FAB to be dragged. Default: false. */
|
|
204
|
+
draggable?: boolean;
|
|
205
|
+
/** Snap FAB to the nearest vertical edge on release. Default: true. */
|
|
206
|
+
snapToEdge?: boolean;
|
|
207
|
+
/** Persist FAB position across app restarts via AsyncStorage. Default: false. */
|
|
208
|
+
persist?: boolean;
|
|
209
|
+
}
|
|
214
210
|
interface MushiFloatingButtonProps {
|
|
215
211
|
onPress: () => void;
|
|
216
212
|
position?: 'bottom-right' | 'bottom-left';
|
|
@@ -219,6 +215,10 @@ interface MushiFloatingButtonProps {
|
|
|
219
215
|
left?: number;
|
|
220
216
|
right?: number;
|
|
221
217
|
};
|
|
218
|
+
/** Draggable + persist config */
|
|
219
|
+
config?: MushiFloatingButtonConfig;
|
|
220
|
+
/** Accent color (hex) — falls back to platform blue */
|
|
221
|
+
accent?: string;
|
|
222
222
|
}
|
|
223
223
|
declare const MushiFloatingButton: FC<MushiFloatingButtonProps>;
|
|
224
224
|
|
package/dist/index.d.ts
CHANGED
|
@@ -188,29 +188,25 @@ interface MushiBottomSheetProps {
|
|
|
188
188
|
declare const MushiBottomSheet: FC<MushiBottomSheetProps>;
|
|
189
189
|
|
|
190
190
|
/**
|
|
191
|
-
*
|
|
192
|
-
* PURPOSE: Floating action button (FAB) that triggers the Mushi bug-report bottom sheet
|
|
191
|
+
* MushiFloatingButton — draggable, repositionable FAB for the Mushi SDK.
|
|
193
192
|
*
|
|
194
|
-
*
|
|
195
|
-
* -
|
|
196
|
-
* -
|
|
197
|
-
* -
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
* -
|
|
201
|
-
*
|
|
202
|
-
* USAGE:
|
|
203
|
-
* - Rendered automatically by MushiProvider when widget.trigger is 'button' or 'both'
|
|
204
|
-
* - Can be used standalone: <MushiFloatingButton onPress={…} />
|
|
205
|
-
*
|
|
206
|
-
* TECHNICAL DETAILS:
|
|
207
|
-
* - Uses Animated.Value for scale, driven by onPressIn / onPressOut
|
|
208
|
-
* - Safe-area aware: extra bottom padding on iOS
|
|
209
|
-
*
|
|
210
|
-
* NOTES:
|
|
211
|
-
* - Keeps zIndex high (9999) so it floats above app content
|
|
193
|
+
* Supports:
|
|
194
|
+
* - PanResponder drag with tap-vs-drag threshold (6 px)
|
|
195
|
+
* - Clamp to screen bounds with safe-area respect
|
|
196
|
+
* - Optional edge-snap on release (`snapToEdge`)
|
|
197
|
+
* - Persist position to AsyncStorage (opt-in via `persist` config)
|
|
198
|
+
* - Press-in / press-out spring scale animation
|
|
199
|
+
* - Dark/light adaptive colours
|
|
212
200
|
*/
|
|
213
201
|
|
|
202
|
+
interface MushiFloatingButtonConfig {
|
|
203
|
+
/** Allow the FAB to be dragged. Default: false. */
|
|
204
|
+
draggable?: boolean;
|
|
205
|
+
/** Snap FAB to the nearest vertical edge on release. Default: true. */
|
|
206
|
+
snapToEdge?: boolean;
|
|
207
|
+
/** Persist FAB position across app restarts via AsyncStorage. Default: false. */
|
|
208
|
+
persist?: boolean;
|
|
209
|
+
}
|
|
214
210
|
interface MushiFloatingButtonProps {
|
|
215
211
|
onPress: () => void;
|
|
216
212
|
position?: 'bottom-right' | 'bottom-left';
|
|
@@ -219,6 +215,10 @@ interface MushiFloatingButtonProps {
|
|
|
219
215
|
left?: number;
|
|
220
216
|
right?: number;
|
|
221
217
|
};
|
|
218
|
+
/** Draggable + persist config */
|
|
219
|
+
config?: MushiFloatingButtonConfig;
|
|
220
|
+
/** Accent color (hex) — falls back to platform blue */
|
|
221
|
+
accent?: string;
|
|
222
222
|
}
|
|
223
223
|
declare const MushiFloatingButton: FC<MushiFloatingButtonProps>;
|
|
224
224
|
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
9
9
|
import {
|
|
10
10
|
createContext,
|
|
11
11
|
useContext,
|
|
12
|
-
useEffect as
|
|
12
|
+
useEffect as useEffect3,
|
|
13
13
|
useRef as useRef3,
|
|
14
14
|
useState as useState2,
|
|
15
15
|
useCallback as useCallback3,
|
|
@@ -306,6 +306,7 @@ import {
|
|
|
306
306
|
Dimensions as Dimensions2,
|
|
307
307
|
Platform as Platform2,
|
|
308
308
|
KeyboardAvoidingView,
|
|
309
|
+
ScrollView,
|
|
309
310
|
useColorScheme
|
|
310
311
|
} from "react-native";
|
|
311
312
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -319,6 +320,7 @@ var CATEGORIES = [
|
|
|
319
320
|
{ key: "confusing", emoji: "\u{1F615}", label: "Confusing" },
|
|
320
321
|
{ key: "other", emoji: "\u{1F4AC}", label: "Other" }
|
|
321
322
|
];
|
|
323
|
+
var VERIFIABLE_STATUSES = /* @__PURE__ */ new Set(["fixed", "resolved", "verified"]);
|
|
322
324
|
var MushiBottomSheet = ({
|
|
323
325
|
visible,
|
|
324
326
|
onClose,
|
|
@@ -340,12 +342,6 @@ var MushiBottomSheet = ({
|
|
|
340
342
|
const [threadComments, setThreadComments] = useState([]);
|
|
341
343
|
const [replyText, setReplyText] = useState("");
|
|
342
344
|
const [screenshotAttached, setScreenshotAttached] = useState(true);
|
|
343
|
-
useEffect(() => {
|
|
344
|
-
if (visible) {
|
|
345
|
-
setScreenshotAttached(true);
|
|
346
|
-
if (sheetTab === "inbox") void loadInbox();
|
|
347
|
-
}
|
|
348
|
-
}, [visible, sheetTab]);
|
|
349
345
|
const loadInbox = useCallback(async () => {
|
|
350
346
|
if (!mushi?.listMyReports) return;
|
|
351
347
|
setInboxLoading(true);
|
|
@@ -356,6 +352,12 @@ var MushiBottomSheet = ({
|
|
|
356
352
|
setInboxLoading(false);
|
|
357
353
|
}
|
|
358
354
|
}, [mushi]);
|
|
355
|
+
useEffect(() => {
|
|
356
|
+
if (visible) {
|
|
357
|
+
setScreenshotAttached(true);
|
|
358
|
+
if (sheetTab === "inbox") void loadInbox();
|
|
359
|
+
}
|
|
360
|
+
}, [visible, sheetTab, loadInbox]);
|
|
359
361
|
const openThread = useCallback(async (reportId) => {
|
|
360
362
|
setSelectedReportId(reportId);
|
|
361
363
|
if (!mushi?.listMyComments) return;
|
|
@@ -457,13 +459,14 @@ var MushiBottomSheet = ({
|
|
|
457
459
|
}
|
|
458
460
|
};
|
|
459
461
|
const activeScreenshot = screenshotDataUrl && screenshotAttached ? screenshotDataUrl : null;
|
|
460
|
-
const colors = dark ? { bg: "#1c1c1e", text: "#f2f2f7", sub: "#8e8e93", card: "#2c2c2e", accent: "#0a84ff", border: "#38383a", backdrop: "rgba(0,0,0,0.6)" } : { bg: "#ffffff", text: "#1c1c1e", sub: "#8e8e93", card: "#f2f2f7", accent: "#007aff", border: "#e5e5ea", backdrop: "rgba(0,0,0,0.35)" };
|
|
462
|
+
const colors = dark ? { bg: "#1c1c1e", text: "#f2f2f7", sub: "#8e8e93", card: "#2c2c2e", accent: "#0a84ff", border: "#38383a", backdrop: "rgba(0,0,0,0.6)", disabled: "#3a3a3c", disabledText: "#636366" } : { bg: "#ffffff", text: "#1c1c1e", sub: "#8e8e93", card: "#f2f2f7", accent: "#007aff", border: "#e5e5ea", backdrop: "rgba(0,0,0,0.35)", disabled: "#d1d1d6", disabledText: "#8e8e93" };
|
|
461
463
|
const canSubmit = !!category && description.trim().length > 0 && phase === "form";
|
|
462
464
|
return /* @__PURE__ */ jsx(Modal, { visible, transparent: true, animationType: "none", statusBarTranslucent: true, children: /* @__PURE__ */ jsxs(
|
|
463
465
|
KeyboardAvoidingView,
|
|
464
466
|
{
|
|
465
467
|
style: s.flex,
|
|
466
|
-
behavior: Platform2.OS === "ios" ? "padding" :
|
|
468
|
+
behavior: Platform2.OS === "ios" ? "padding" : "height",
|
|
469
|
+
keyboardVerticalOffset: Platform2.OS === "ios" ? 0 : 20,
|
|
467
470
|
children: [
|
|
468
471
|
/* @__PURE__ */ jsx(
|
|
469
472
|
Animated.View,
|
|
@@ -481,7 +484,7 @@ var MushiBottomSheet = ({
|
|
|
481
484
|
],
|
|
482
485
|
children: [
|
|
483
486
|
/* @__PURE__ */ jsx(View, { ...panResponder.panHandlers, style: s.handleArea, children: /* @__PURE__ */ jsx(View, { style: [s.handle, { backgroundColor: colors.sub }] }) }),
|
|
484
|
-
/* @__PURE__ */ jsx(View, { style: s.tabRow, children: ["report", "inbox"].map((tab) => /* @__PURE__ */ jsx(
|
|
487
|
+
/* @__PURE__ */ jsx(View, { style: s.tabRow, children: ["report", "inbox", "community"].map((tab) => /* @__PURE__ */ jsx(
|
|
485
488
|
TouchableOpacity,
|
|
486
489
|
{
|
|
487
490
|
onPress: () => {
|
|
@@ -490,17 +493,19 @@ var MushiBottomSheet = ({
|
|
|
490
493
|
else setSelectedReportId(null);
|
|
491
494
|
},
|
|
492
495
|
style: [s.tabBtn, sheetTab === tab && { borderBottomColor: colors.accent }],
|
|
493
|
-
children: /* @__PURE__ */ jsx(Text, { style: [s.tabLabel, { color: sheetTab === tab ? colors.accent : colors.sub }], children: tab === "report" ? "Report" : "Inbox" })
|
|
496
|
+
children: /* @__PURE__ */ jsx(Text, { style: [s.tabLabel, { color: sheetTab === tab ? colors.accent : colors.sub }], children: tab === "report" ? "Report" : tab === "inbox" ? "Inbox" : "\u{1F310}" })
|
|
494
497
|
},
|
|
495
498
|
tab
|
|
496
499
|
)) }),
|
|
497
|
-
sheetTab === "inbox" ? /* @__PURE__ */ jsx(
|
|
500
|
+
sheetTab === "inbox" ? /* @__PURE__ */ jsx(ScrollView, { style: s.body, keyboardShouldPersistTaps: "handled", children: inboxLoading ? /* @__PURE__ */ jsx(Text, { style: { color: colors.sub }, children: "Loading\u2026" }) : selectedReportId ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
498
501
|
/* @__PURE__ */ jsx(TouchableOpacity, { onPress: () => setSelectedReportId(null), children: /* @__PURE__ */ jsx(Text, { style: { color: colors.accent, marginBottom: 8 }, children: "\u2190 Back" }) }),
|
|
499
502
|
threadComments.map((c) => /* @__PURE__ */ jsxs(View, { style: [s.threadBubble, { backgroundColor: colors.card }], children: [
|
|
500
503
|
/* @__PURE__ */ jsx(Text, { style: { color: colors.sub, fontSize: 11 }, children: c.author_kind }),
|
|
501
504
|
/* @__PURE__ */ jsx(Text, { style: { color: colors.text }, children: c.body })
|
|
502
505
|
] }, c.id)),
|
|
503
|
-
|
|
506
|
+
VERIFIABLE_STATUSES.has(
|
|
507
|
+
inboxReports.find((r) => r.id === selectedReportId)?.status ?? ""
|
|
508
|
+
) && /* @__PURE__ */ jsxs(View, { style: s.verifyRow, children: [
|
|
504
509
|
/* @__PURE__ */ jsx(TouchableOpacity, { style: [s.verifyBtn, { backgroundColor: colors.accent }], onPress: () => submitFeedback("confirms"), children: /* @__PURE__ */ jsx(Text, { style: s.submitText, children: "Yes, fixed" }) }),
|
|
505
510
|
/* @__PURE__ */ jsx(TouchableOpacity, { style: [s.verifyBtn, { backgroundColor: colors.border }], onPress: () => submitFeedback("not_fixed"), children: /* @__PURE__ */ jsx(Text, { style: [s.submitText, { color: colors.text }], children: "Not fixed" }) })
|
|
506
511
|
] }),
|
|
@@ -518,102 +523,127 @@ var MushiBottomSheet = ({
|
|
|
518
523
|
] }) : inboxReports.map((r) => /* @__PURE__ */ jsxs(TouchableOpacity, { style: [s.inboxRow, { borderColor: colors.border }], onPress: () => openThread(r.id), children: [
|
|
519
524
|
/* @__PURE__ */ jsx(Text, { style: { color: colors.text, fontWeight: "600" }, numberOfLines: 1, children: (r.summary ?? r.description ?? "Report").slice(0, 60) }),
|
|
520
525
|
/* @__PURE__ */ jsx(Text, { style: { color: colors.sub, fontSize: 11 }, children: r.status })
|
|
521
|
-
] }, r.id)) }) :
|
|
526
|
+
] }, r.id)) }) : sheetTab === "community" ? /* @__PURE__ */ jsxs(ScrollView, { style: s.body, keyboardShouldPersistTaps: "handled", children: [
|
|
527
|
+
/* @__PURE__ */ jsx(Text, { style: [s.title, { color: colors.text }], children: "\u{1F310} Mushi Community" }),
|
|
528
|
+
/* @__PURE__ */ jsx(Text, { style: { color: colors.sub, fontSize: 13, marginBottom: 16, lineHeight: 18 }, children: "Sign in to track your reports across apps and see the global leaderboard. No password needed." }),
|
|
529
|
+
/* @__PURE__ */ jsx(
|
|
530
|
+
TextInput,
|
|
531
|
+
{
|
|
532
|
+
style: [s.input, { backgroundColor: colors.card, color: colors.text, borderColor: colors.border, minHeight: 48 }],
|
|
533
|
+
placeholder: "you@example.com",
|
|
534
|
+
placeholderTextColor: colors.sub,
|
|
535
|
+
keyboardType: "email-address",
|
|
536
|
+
autoCapitalize: "none",
|
|
537
|
+
autoCorrect: false,
|
|
538
|
+
textContentType: "emailAddress"
|
|
539
|
+
}
|
|
540
|
+
),
|
|
541
|
+
/* @__PURE__ */ jsx(TouchableOpacity, { style: [s.submitBtn, { backgroundColor: colors.accent }], children: /* @__PURE__ */ jsx(Text, { style: s.submitText, children: "Send sign-in link \u2192" }) }),
|
|
542
|
+
/* @__PURE__ */ jsx(Text, { style: { color: colors.sub, fontSize: 11, textAlign: "center", marginTop: 12 }, children: "We'll email you a one-tap sign-in link. No password, ever." })
|
|
543
|
+
] }) : phase === "sent" ? /* @__PURE__ */ jsxs(View, { style: s.sentWrap, children: [
|
|
522
544
|
/* @__PURE__ */ jsx(Text, { style: [s.sentEmoji], children: "\u2705" }),
|
|
523
545
|
/* @__PURE__ */ jsx(Text, { style: [s.sentText, { color: colors.text }], children: "Report sent!" })
|
|
524
|
-
] }) : /* @__PURE__ */ jsxs(
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
546
|
+
] }) : /* @__PURE__ */ jsxs(
|
|
547
|
+
ScrollView,
|
|
548
|
+
{
|
|
549
|
+
style: s.body,
|
|
550
|
+
keyboardShouldPersistTaps: "handled",
|
|
551
|
+
contentContainerStyle: { paddingBottom: 24 },
|
|
552
|
+
children: [
|
|
553
|
+
/* @__PURE__ */ jsx(Text, { style: [s.title, { color: colors.text }], children: "Report an issue" }),
|
|
554
|
+
/* @__PURE__ */ jsx(View, { style: s.catRow, children: CATEGORIES.map((c) => {
|
|
555
|
+
const active = category === c.key;
|
|
556
|
+
return /* @__PURE__ */ jsxs(
|
|
557
|
+
TouchableOpacity,
|
|
535
558
|
{
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
559
|
+
onPress: () => setCategory(c.key),
|
|
560
|
+
activeOpacity: 0.7,
|
|
561
|
+
style: [
|
|
562
|
+
s.catBtn,
|
|
563
|
+
{
|
|
564
|
+
backgroundColor: active ? colors.accent : colors.card,
|
|
565
|
+
borderColor: active ? colors.accent : colors.border
|
|
566
|
+
}
|
|
567
|
+
],
|
|
568
|
+
children: [
|
|
569
|
+
/* @__PURE__ */ jsx(Text, { style: s.catEmoji, children: c.emoji }),
|
|
570
|
+
/* @__PURE__ */ jsx(
|
|
571
|
+
Text,
|
|
572
|
+
{
|
|
573
|
+
style: [
|
|
574
|
+
s.catLabel,
|
|
575
|
+
{ color: active ? "#fff" : colors.text }
|
|
576
|
+
],
|
|
577
|
+
children: c.label
|
|
578
|
+
}
|
|
579
|
+
)
|
|
580
|
+
]
|
|
581
|
+
},
|
|
582
|
+
c.key
|
|
583
|
+
);
|
|
584
|
+
}) }),
|
|
585
|
+
/* @__PURE__ */ jsx(
|
|
586
|
+
TextInput,
|
|
587
|
+
{
|
|
588
|
+
style: [
|
|
589
|
+
s.input,
|
|
544
590
|
{
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
],
|
|
549
|
-
children: c.label
|
|
591
|
+
backgroundColor: colors.card,
|
|
592
|
+
color: colors.text,
|
|
593
|
+
borderColor: colors.border
|
|
550
594
|
}
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
595
|
+
],
|
|
596
|
+
placeholder: "What happened?",
|
|
597
|
+
placeholderTextColor: colors.sub,
|
|
598
|
+
multiline: true,
|
|
599
|
+
textAlignVertical: "top",
|
|
600
|
+
value: description,
|
|
601
|
+
onChangeText: setDescription,
|
|
602
|
+
editable: phase === "form"
|
|
603
|
+
}
|
|
604
|
+
),
|
|
605
|
+
activeScreenshot ? /* @__PURE__ */ jsxs(View, { style: s.screenshotRow, children: [
|
|
606
|
+
/* @__PURE__ */ jsx(
|
|
607
|
+
Image,
|
|
608
|
+
{
|
|
609
|
+
source: { uri: activeScreenshot },
|
|
610
|
+
style: s.screenshotThumb,
|
|
611
|
+
accessibilityLabel: "Attached screenshot"
|
|
612
|
+
}
|
|
613
|
+
),
|
|
614
|
+
/* @__PURE__ */ jsxs(View, { style: s.screenshotMeta, children: [
|
|
615
|
+
/* @__PURE__ */ jsx(Text, { style: [s.screenshotLabel, { color: colors.text }], children: "Screenshot attached" }),
|
|
616
|
+
/* @__PURE__ */ jsx(Text, { style: [s.screenshotSub, { color: colors.sub }], children: "Helps the team see the issue" })
|
|
617
|
+
] }),
|
|
618
|
+
/* @__PURE__ */ jsx(
|
|
619
|
+
TouchableOpacity,
|
|
620
|
+
{
|
|
621
|
+
onPress: () => {
|
|
622
|
+
setScreenshotAttached(false);
|
|
623
|
+
onClearScreenshot?.();
|
|
624
|
+
},
|
|
625
|
+
hitSlop: { top: 8, bottom: 8, left: 8, right: 8 },
|
|
626
|
+
accessibilityLabel: "Remove screenshot",
|
|
627
|
+
children: /* @__PURE__ */ jsx(Text, { style: [s.screenshotRemove, { color: colors.sub }], children: "\u2715" })
|
|
628
|
+
}
|
|
629
|
+
)
|
|
630
|
+
] }) : null,
|
|
631
|
+
/* @__PURE__ */ jsx(
|
|
632
|
+
TouchableOpacity,
|
|
562
633
|
{
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
634
|
+
onPress: handleSubmit,
|
|
635
|
+
disabled: !canSubmit,
|
|
636
|
+
activeOpacity: 0.8,
|
|
637
|
+
style: [
|
|
638
|
+
s.submitBtn,
|
|
639
|
+
{ backgroundColor: canSubmit ? colors.accent : colors.disabled }
|
|
640
|
+
],
|
|
641
|
+
children: /* @__PURE__ */ jsx(Text, { style: [s.submitText, !canSubmit && { color: colors.disabledText }], children: phase === "sending" ? "Sending\u2026" : "Submit" })
|
|
566
642
|
}
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
textAlignVertical: "top",
|
|
572
|
-
value: description,
|
|
573
|
-
onChangeText: setDescription,
|
|
574
|
-
editable: phase === "form"
|
|
575
|
-
}
|
|
576
|
-
),
|
|
577
|
-
activeScreenshot ? /* @__PURE__ */ jsxs(View, { style: s.screenshotRow, children: [
|
|
578
|
-
/* @__PURE__ */ jsx(
|
|
579
|
-
Image,
|
|
580
|
-
{
|
|
581
|
-
source: { uri: activeScreenshot },
|
|
582
|
-
style: s.screenshotThumb,
|
|
583
|
-
accessibilityLabel: "Attached screenshot"
|
|
584
|
-
}
|
|
585
|
-
),
|
|
586
|
-
/* @__PURE__ */ jsxs(View, { style: s.screenshotMeta, children: [
|
|
587
|
-
/* @__PURE__ */ jsx(Text, { style: [s.screenshotLabel, { color: colors.text }], children: "Screenshot attached" }),
|
|
588
|
-
/* @__PURE__ */ jsx(Text, { style: [s.screenshotSub, { color: colors.sub }], children: "Helps the team see the issue" })
|
|
589
|
-
] }),
|
|
590
|
-
/* @__PURE__ */ jsx(
|
|
591
|
-
TouchableOpacity,
|
|
592
|
-
{
|
|
593
|
-
onPress: () => {
|
|
594
|
-
setScreenshotAttached(false);
|
|
595
|
-
onClearScreenshot?.();
|
|
596
|
-
},
|
|
597
|
-
hitSlop: { top: 8, bottom: 8, left: 8, right: 8 },
|
|
598
|
-
accessibilityLabel: "Remove screenshot",
|
|
599
|
-
children: /* @__PURE__ */ jsx(Text, { style: [s.screenshotRemove, { color: colors.sub }], children: "\u2715" })
|
|
600
|
-
}
|
|
601
|
-
)
|
|
602
|
-
] }) : null,
|
|
603
|
-
/* @__PURE__ */ jsx(
|
|
604
|
-
TouchableOpacity,
|
|
605
|
-
{
|
|
606
|
-
onPress: handleSubmit,
|
|
607
|
-
disabled: !canSubmit,
|
|
608
|
-
activeOpacity: 0.8,
|
|
609
|
-
style: [
|
|
610
|
-
s.submitBtn,
|
|
611
|
-
{ backgroundColor: canSubmit ? colors.accent : colors.border }
|
|
612
|
-
],
|
|
613
|
-
children: /* @__PURE__ */ jsx(Text, { style: s.submitText, children: phase === "sending" ? "Sending\u2026" : "Submit" })
|
|
614
|
-
}
|
|
615
|
-
)
|
|
616
|
-
] })
|
|
643
|
+
)
|
|
644
|
+
]
|
|
645
|
+
}
|
|
646
|
+
)
|
|
617
647
|
]
|
|
618
648
|
}
|
|
619
649
|
)
|
|
@@ -786,24 +816,143 @@ var s = StyleSheet.create({
|
|
|
786
816
|
});
|
|
787
817
|
|
|
788
818
|
// src/components/MushiFloatingButton.tsx
|
|
789
|
-
import { useRef as useRef2, useCallback as useCallback2 } from "react";
|
|
819
|
+
import { useRef as useRef2, useCallback as useCallback2, useEffect as useEffect2 } from "react";
|
|
790
820
|
import {
|
|
791
821
|
Animated as Animated2,
|
|
792
|
-
|
|
822
|
+
PanResponder as PanResponder2,
|
|
793
823
|
StyleSheet as StyleSheet2,
|
|
794
824
|
Platform as Platform3,
|
|
825
|
+
Dimensions as Dimensions3,
|
|
795
826
|
useColorScheme as useColorScheme2
|
|
796
827
|
} from "react-native";
|
|
797
828
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
829
|
+
var FAB_SIZE = 56;
|
|
830
|
+
var EDGE_PADDING = 12;
|
|
831
|
+
function getScreenBounds() {
|
|
832
|
+
const { width, height } = Dimensions3.get("window");
|
|
833
|
+
return { width, height };
|
|
834
|
+
}
|
|
835
|
+
function clamp(value, min, max) {
|
|
836
|
+
return Math.min(Math.max(value, min), max);
|
|
837
|
+
}
|
|
838
|
+
var STORAGE_KEY = "mushi:fab-pos";
|
|
839
|
+
async function loadStoredPos() {
|
|
840
|
+
try {
|
|
841
|
+
const AsyncStorage = (await import("@react-native-async-storage/async-storage")).default;
|
|
842
|
+
const raw = await AsyncStorage.getItem(STORAGE_KEY);
|
|
843
|
+
if (!raw) return null;
|
|
844
|
+
return JSON.parse(raw);
|
|
845
|
+
} catch {
|
|
846
|
+
return null;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
async function storePos(pos) {
|
|
850
|
+
try {
|
|
851
|
+
const AsyncStorage = (await import("@react-native-async-storage/async-storage")).default;
|
|
852
|
+
await AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(pos));
|
|
853
|
+
} catch {
|
|
854
|
+
}
|
|
855
|
+
}
|
|
798
856
|
var MushiFloatingButton = ({
|
|
799
857
|
onPress,
|
|
800
858
|
position = "bottom-right",
|
|
801
|
-
inset
|
|
859
|
+
inset,
|
|
860
|
+
config,
|
|
861
|
+
accent
|
|
802
862
|
}) => {
|
|
803
863
|
const scheme = useColorScheme2();
|
|
804
864
|
const dark = scheme === "dark";
|
|
865
|
+
const draggable = config?.draggable ?? false;
|
|
866
|
+
const snapToEdge = config?.snapToEdge ?? true;
|
|
867
|
+
const persist = config?.persist ?? false;
|
|
868
|
+
const baseBottom = inset?.bottom ?? (Platform3.OS === "ios" ? 50 : 28);
|
|
869
|
+
const baseX = position === "bottom-left" ? inset?.left ?? EDGE_PADDING : (() => {
|
|
870
|
+
const { width } = getScreenBounds();
|
|
871
|
+
return width - FAB_SIZE - (inset?.right ?? EDGE_PADDING);
|
|
872
|
+
})();
|
|
805
873
|
const scale = useRef2(new Animated2.Value(1)).current;
|
|
874
|
+
const posX = useRef2(new Animated2.Value(baseX)).current;
|
|
875
|
+
const posY = useRef2(new Animated2.Value(0)).current;
|
|
876
|
+
const currentX = useRef2(baseX);
|
|
877
|
+
const currentY = useRef2(0);
|
|
878
|
+
const isDragging = useRef2(false);
|
|
879
|
+
const accentColor = accent ?? (dark ? "#0a84ff" : "#007aff");
|
|
880
|
+
useEffect2(() => {
|
|
881
|
+
if (!persist) return;
|
|
882
|
+
void loadStoredPos().then((pos) => {
|
|
883
|
+
if (!pos) return;
|
|
884
|
+
currentX.current = pos.x;
|
|
885
|
+
currentY.current = pos.y;
|
|
886
|
+
posX.setValue(pos.x);
|
|
887
|
+
posY.setValue(pos.y);
|
|
888
|
+
});
|
|
889
|
+
}, [persist, posX, posY]);
|
|
890
|
+
const snapAndPersist = useCallback2(
|
|
891
|
+
(x, y) => {
|
|
892
|
+
const { width, height } = getScreenBounds();
|
|
893
|
+
let snappedX = x;
|
|
894
|
+
if (snapToEdge) {
|
|
895
|
+
const midX = width / 2;
|
|
896
|
+
snappedX = x + FAB_SIZE / 2 < midX ? EDGE_PADDING : width - FAB_SIZE - EDGE_PADDING;
|
|
897
|
+
}
|
|
898
|
+
const clampedX = clamp(snappedX, EDGE_PADDING, width - FAB_SIZE - EDGE_PADDING);
|
|
899
|
+
const clampedY = clamp(y, -(height - FAB_SIZE - baseBottom - 60), 0);
|
|
900
|
+
currentX.current = clampedX;
|
|
901
|
+
currentY.current = clampedY;
|
|
902
|
+
Animated2.spring(posX, {
|
|
903
|
+
toValue: clampedX,
|
|
904
|
+
useNativeDriver: false,
|
|
905
|
+
damping: 18,
|
|
906
|
+
stiffness: 220
|
|
907
|
+
}).start();
|
|
908
|
+
Animated2.spring(posY, {
|
|
909
|
+
toValue: clampedY,
|
|
910
|
+
useNativeDriver: false,
|
|
911
|
+
damping: 18,
|
|
912
|
+
stiffness: 220
|
|
913
|
+
}).start();
|
|
914
|
+
if (persist) void storePos({ x: clampedX, y: clampedY });
|
|
915
|
+
},
|
|
916
|
+
[snapToEdge, persist, posX, posY, baseBottom]
|
|
917
|
+
);
|
|
918
|
+
const panResponder = useRef2(
|
|
919
|
+
draggable ? PanResponder2.create({
|
|
920
|
+
onStartShouldSetPanResponder: () => true,
|
|
921
|
+
onMoveShouldSetPanResponder: (_, g) => Math.abs(g.dx) > 6 || Math.abs(g.dy) > 6,
|
|
922
|
+
onPanResponderGrant: () => {
|
|
923
|
+
isDragging.current = false;
|
|
924
|
+
posX.stopAnimation();
|
|
925
|
+
posY.stopAnimation();
|
|
926
|
+
},
|
|
927
|
+
onPanResponderMove: (_, g) => {
|
|
928
|
+
if (Math.abs(g.dx) > 6 || Math.abs(g.dy) > 6) {
|
|
929
|
+
isDragging.current = true;
|
|
930
|
+
scale.setValue(1);
|
|
931
|
+
}
|
|
932
|
+
const { width, height } = getScreenBounds();
|
|
933
|
+
const newX = clamp(
|
|
934
|
+
currentX.current + g.dx,
|
|
935
|
+
EDGE_PADDING,
|
|
936
|
+
width - FAB_SIZE - EDGE_PADDING
|
|
937
|
+
);
|
|
938
|
+
const newY = clamp(
|
|
939
|
+
currentY.current + g.dy,
|
|
940
|
+
-(height - FAB_SIZE - baseBottom - 60),
|
|
941
|
+
0
|
|
942
|
+
);
|
|
943
|
+
posX.setValue(newX);
|
|
944
|
+
posY.setValue(newY);
|
|
945
|
+
},
|
|
946
|
+
onPanResponderRelease: (_, g) => {
|
|
947
|
+
if (isDragging.current) {
|
|
948
|
+
snapAndPersist(currentX.current + g.dx, currentY.current + g.dy);
|
|
949
|
+
}
|
|
950
|
+
isDragging.current = false;
|
|
951
|
+
}
|
|
952
|
+
}) : PanResponder2.create({})
|
|
953
|
+
).current;
|
|
806
954
|
const handlePressIn = useCallback2(() => {
|
|
955
|
+
if (isDragging.current) return;
|
|
807
956
|
Animated2.spring(scale, {
|
|
808
957
|
toValue: 0.85,
|
|
809
958
|
useNativeDriver: true,
|
|
@@ -818,39 +967,35 @@ var MushiFloatingButton = ({
|
|
|
818
967
|
damping: 10,
|
|
819
968
|
stiffness: 250
|
|
820
969
|
}).start();
|
|
821
|
-
|
|
822
|
-
|
|
970
|
+
if (!isDragging.current) onPress();
|
|
971
|
+
}, [scale, onPress]);
|
|
823
972
|
return /* @__PURE__ */ jsx2(
|
|
824
|
-
|
|
973
|
+
Animated2.View,
|
|
825
974
|
{
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
children: /* @__PURE__ */ jsx2(
|
|
830
|
-
Animated2.View,
|
|
975
|
+
...draggable ? panResponder.panHandlers : {},
|
|
976
|
+
style: [
|
|
977
|
+
s2.fab,
|
|
831
978
|
{
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
backgroundColor: dark ? "#0a84ff" : "#007aff",
|
|
838
|
-
transform: [{ scale }],
|
|
839
|
-
shadowColor: dark ? "#0a84ff" : "#000"
|
|
840
|
-
}
|
|
841
|
-
],
|
|
842
|
-
children: /* @__PURE__ */ jsx2(Animated2.Text, { style: s2.emoji, children: "\u{1F41B}" })
|
|
979
|
+
left: posX,
|
|
980
|
+
bottom: Animated2.add(new Animated2.Value(baseBottom), Animated2.multiply(posY, -1)),
|
|
981
|
+
backgroundColor: accentColor,
|
|
982
|
+
shadowColor: dark ? accentColor : "#000",
|
|
983
|
+
transform: [{ scale }]
|
|
843
984
|
}
|
|
844
|
-
|
|
985
|
+
],
|
|
986
|
+
onStartShouldSetResponder: () => !draggable,
|
|
987
|
+
onResponderGrant: handlePressIn,
|
|
988
|
+
onResponderRelease: handlePressOut,
|
|
989
|
+
children: /* @__PURE__ */ jsx2(Animated2.Text, { style: s2.emoji, children: "\u{1F41B}" })
|
|
845
990
|
}
|
|
846
991
|
);
|
|
847
992
|
};
|
|
848
993
|
var s2 = StyleSheet2.create({
|
|
849
994
|
fab: {
|
|
850
995
|
position: "absolute",
|
|
851
|
-
width:
|
|
852
|
-
height:
|
|
853
|
-
borderRadius:
|
|
996
|
+
width: FAB_SIZE,
|
|
997
|
+
height: FAB_SIZE,
|
|
998
|
+
borderRadius: FAB_SIZE / 2,
|
|
854
999
|
alignItems: "center",
|
|
855
1000
|
justifyContent: "center",
|
|
856
1001
|
zIndex: 9999,
|
|
@@ -892,7 +1037,7 @@ function MushiProvider({ children, ...config }) {
|
|
|
892
1037
|
console.warn("[MushiProvider] `endpoint` is deprecated \u2014 use `apiEndpoint` instead.");
|
|
893
1038
|
}
|
|
894
1039
|
const apiEndpoint = rawEndpoint ?? DEFAULT_API_ENDPOINT;
|
|
895
|
-
|
|
1040
|
+
useEffect3(() => {
|
|
896
1041
|
if (config.capture?.console !== false) {
|
|
897
1042
|
consoleRef.current = setupConsoleCapture(config.capture?.maxConsoleEntries);
|
|
898
1043
|
}
|
|
@@ -941,7 +1086,7 @@ function MushiProvider({ children, ...config }) {
|
|
|
941
1086
|
networkRef.current?.restore();
|
|
942
1087
|
};
|
|
943
1088
|
}, []);
|
|
944
|
-
|
|
1089
|
+
useEffect3(() => {
|
|
945
1090
|
let unsubscribe;
|
|
946
1091
|
try {
|
|
947
1092
|
const NetInfo = __require("@react-native-community/netinfo").default;
|
|
@@ -976,7 +1121,7 @@ function MushiProvider({ children, ...config }) {
|
|
|
976
1121
|
}, []);
|
|
977
1122
|
const close = useCallback3(() => setSheetVisible(false), []);
|
|
978
1123
|
const attachTo = useCallback3(() => ({ onPress: open }), [open]);
|
|
979
|
-
|
|
1124
|
+
useEffect3(() => {
|
|
980
1125
|
const trigger2 = config.widget?.trigger ?? "button";
|
|
981
1126
|
if (trigger2 !== "shake" && trigger2 !== "both") return;
|
|
982
1127
|
let disposed = false;
|
|
@@ -1057,7 +1202,7 @@ function MushiProvider({ children, ...config }) {
|
|
|
1057
1202
|
const screenRef = useRef3(null);
|
|
1058
1203
|
const activityQueueRef = useRef3([]);
|
|
1059
1204
|
const rewardsFlushRef = useRef3(null);
|
|
1060
|
-
|
|
1205
|
+
useEffect3(() => {
|
|
1061
1206
|
const rewards = config.rewards;
|
|
1062
1207
|
if (!rewards?.enabled || !rewards.trackActivity) return;
|
|
1063
1208
|
const flushMs = Math.max(3e4, rewards.flushIntervalMs ?? 3e5);
|
|
@@ -1240,10 +1385,10 @@ function MushiTrigger({ children }) {
|
|
|
1240
1385
|
}
|
|
1241
1386
|
|
|
1242
1387
|
// src/capture/navigation-capture.ts
|
|
1243
|
-
import { useEffect as
|
|
1388
|
+
import { useEffect as useEffect4, useRef as useRef4 } from "react";
|
|
1244
1389
|
function useNavigationCapture(navigationRef) {
|
|
1245
1390
|
const historyRef = useRef4([]);
|
|
1246
|
-
|
|
1391
|
+
useEffect4(() => {
|
|
1247
1392
|
if (!navigationRef?.addListener || !navigationRef?.getCurrentRoute) return;
|
|
1248
1393
|
const unsubscribe = navigationRef.addListener("state", () => {
|
|
1249
1394
|
const route = navigationRef.getCurrentRoute?.();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mushi-mushi/react-native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "React Native SDK for Mushi Mushi — shake-to-report, bottom sheet widget, full context capture",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
}
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@mushi-mushi/core": "^1.
|
|
36
|
+
"@mushi-mushi/core": "^1.14.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/react": "^19.2.14",
|