@dubsdotapp/expo 0.2.75 → 0.2.77
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/dist/index.js +136 -53
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +136 -53
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/hooks/useAuth.ts +10 -4
- package/src/ui/AuthGate.tsx +37 -14
- package/src/ui/UserProfileSheet.tsx +80 -33
package/dist/index.js
CHANGED
|
@@ -2183,6 +2183,12 @@ async function getDeviceInfo() {
|
|
|
2183
2183
|
}
|
|
2184
2184
|
}
|
|
2185
2185
|
|
|
2186
|
+
// src/utils/avatarUrl.ts
|
|
2187
|
+
function ensurePngAvatar(url) {
|
|
2188
|
+
if (!url) return void 0;
|
|
2189
|
+
return url.replace("/svg?", "/png?");
|
|
2190
|
+
}
|
|
2191
|
+
|
|
2186
2192
|
// src/hooks/useAuth.ts
|
|
2187
2193
|
function useAuth() {
|
|
2188
2194
|
const sharedAuth = (0, import_react13.useContext)(AuthContext);
|
|
@@ -2193,6 +2199,10 @@ function useAuth() {
|
|
|
2193
2199
|
const [token, setToken] = (0, import_react13.useState)(null);
|
|
2194
2200
|
const [error, setError] = (0, import_react13.useState)(null);
|
|
2195
2201
|
const pendingAuth = (0, import_react13.useRef)(null);
|
|
2202
|
+
const normalizeUser = (u) => ({
|
|
2203
|
+
...u,
|
|
2204
|
+
avatar: ensurePngAvatar(u.avatar) ?? u.avatar
|
|
2205
|
+
});
|
|
2196
2206
|
const reset = (0, import_react13.useCallback)(() => {
|
|
2197
2207
|
setStatus("idle");
|
|
2198
2208
|
setUser(null);
|
|
@@ -2226,7 +2236,7 @@ function useAuth() {
|
|
|
2226
2236
|
setStatus("needsRegistration");
|
|
2227
2237
|
return;
|
|
2228
2238
|
}
|
|
2229
|
-
setUser(result.user);
|
|
2239
|
+
setUser(normalizeUser(result.user));
|
|
2230
2240
|
setToken(result.token);
|
|
2231
2241
|
setStatus("authenticated");
|
|
2232
2242
|
} catch (err) {
|
|
@@ -2261,7 +2271,7 @@ function useAuth() {
|
|
|
2261
2271
|
});
|
|
2262
2272
|
pendingAuth.current = null;
|
|
2263
2273
|
const user2 = avatarUrl && !result.user.avatar ? { ...result.user, avatar: avatarUrl } : result.user;
|
|
2264
|
-
setUser(user2);
|
|
2274
|
+
setUser(normalizeUser(user2));
|
|
2265
2275
|
setToken(result.token);
|
|
2266
2276
|
setStatus("authenticated");
|
|
2267
2277
|
} catch (err) {
|
|
@@ -2284,7 +2294,7 @@ function useAuth() {
|
|
|
2284
2294
|
try {
|
|
2285
2295
|
client.setToken(savedToken);
|
|
2286
2296
|
const me = await client.getMe();
|
|
2287
|
-
setUser(me);
|
|
2297
|
+
setUser(normalizeUser(me));
|
|
2288
2298
|
setToken(savedToken);
|
|
2289
2299
|
setStatus("authenticated");
|
|
2290
2300
|
return true;
|
|
@@ -2299,7 +2309,7 @@ function useAuth() {
|
|
|
2299
2309
|
const refreshUser = (0, import_react13.useCallback)(async () => {
|
|
2300
2310
|
try {
|
|
2301
2311
|
const me = await client.getMe();
|
|
2302
|
-
setUser(me);
|
|
2312
|
+
setUser(normalizeUser(me));
|
|
2303
2313
|
} catch {
|
|
2304
2314
|
}
|
|
2305
2315
|
}, [client]);
|
|
@@ -2526,11 +2536,23 @@ var DICEBEAR_STYLES = [
|
|
|
2526
2536
|
"big-smile",
|
|
2527
2537
|
"thumbs"
|
|
2528
2538
|
];
|
|
2539
|
+
var BG_COLORS = [
|
|
2540
|
+
"1a1a2e",
|
|
2541
|
+
"f43f5e",
|
|
2542
|
+
"f97316",
|
|
2543
|
+
"eab308",
|
|
2544
|
+
"22c55e",
|
|
2545
|
+
"3b82f6",
|
|
2546
|
+
"8b5cf6",
|
|
2547
|
+
"ec4899",
|
|
2548
|
+
"06b6d4",
|
|
2549
|
+
"64748b"
|
|
2550
|
+
];
|
|
2529
2551
|
function generateSeed() {
|
|
2530
2552
|
return Math.random().toString(36).slice(2, 10);
|
|
2531
2553
|
}
|
|
2532
|
-
function getAvatarUrl(style, seed, size = 256) {
|
|
2533
|
-
return `https://api.dicebear.com/9.x/${style}/png?seed=${seed}&size=${size}`;
|
|
2554
|
+
function getAvatarUrl(style, seed, bg = "1a1a2e", size = 256) {
|
|
2555
|
+
return `https://api.dicebear.com/9.x/${style}/png?seed=${seed}&backgroundColor=${bg}&size=${size}`;
|
|
2534
2556
|
}
|
|
2535
2557
|
function AuthGate({
|
|
2536
2558
|
children,
|
|
@@ -2710,6 +2732,7 @@ function DefaultRegistrationScreen({
|
|
|
2710
2732
|
const [step, setStep] = (0, import_react17.useState)(0);
|
|
2711
2733
|
const [avatarSeed, setAvatarSeed] = (0, import_react17.useState)(generateSeed);
|
|
2712
2734
|
const [avatarStyle, setAvatarStyle] = (0, import_react17.useState)("adventurer");
|
|
2735
|
+
const [avatarBg, setAvatarBg] = (0, import_react17.useState)("1a1a2e");
|
|
2713
2736
|
const [showStyles, setShowStyles] = (0, import_react17.useState)(false);
|
|
2714
2737
|
const [username, setUsername] = (0, import_react17.useState)("");
|
|
2715
2738
|
const [referralCode, setReferralCode] = (0, import_react17.useState)("");
|
|
@@ -2718,7 +2741,7 @@ function DefaultRegistrationScreen({
|
|
|
2718
2741
|
const debounceRef = (0, import_react17.useRef)(null);
|
|
2719
2742
|
const fadeAnim = (0, import_react17.useRef)(new import_react_native7.Animated.Value(1)).current;
|
|
2720
2743
|
const slideAnim = (0, import_react17.useRef)(new import_react_native7.Animated.Value(0)).current;
|
|
2721
|
-
const avatarUrl = getAvatarUrl(avatarStyle, avatarSeed);
|
|
2744
|
+
const avatarUrl = getAvatarUrl(avatarStyle, avatarSeed, avatarBg);
|
|
2722
2745
|
(0, import_react17.useEffect)(() => {
|
|
2723
2746
|
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
2724
2747
|
const trimmed = username.trim();
|
|
@@ -2791,15 +2814,30 @@ function DefaultRegistrationScreen({
|
|
|
2791
2814
|
}
|
|
2792
2815
|
)
|
|
2793
2816
|
] }),
|
|
2794
|
-
showStyles && /* @__PURE__ */ (0, import_jsx_runtime3.
|
|
2795
|
-
import_react_native7.
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2817
|
+
showStyles && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
2818
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native7.ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, style: s.styleScroll, children: DICEBEAR_STYLES.map((st) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2819
|
+
import_react_native7.TouchableOpacity,
|
|
2820
|
+
{
|
|
2821
|
+
onPress: () => setAvatarStyle(st),
|
|
2822
|
+
style: [s.styleThumbWrap, { borderColor: st === avatarStyle ? accent : t.border }],
|
|
2823
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native7.Image, { source: { uri: getAvatarUrl(st, avatarSeed, avatarBg, 80) }, style: s.styleThumb })
|
|
2824
|
+
},
|
|
2825
|
+
st
|
|
2826
|
+
)) }),
|
|
2827
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native7.Text, { style: [s.subtitle, { color: t.textMuted, marginTop: 8 }], children: "Background Color" }),
|
|
2828
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native7.ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, style: s.styleScroll, children: BG_COLORS.map((color) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2829
|
+
import_react_native7.TouchableOpacity,
|
|
2830
|
+
{
|
|
2831
|
+
onPress: () => setAvatarBg(color),
|
|
2832
|
+
style: [
|
|
2833
|
+
s.colorSwatch,
|
|
2834
|
+
{ backgroundColor: `#${color}` },
|
|
2835
|
+
color === avatarBg && { borderColor: accent, borderWidth: 2.5 }
|
|
2836
|
+
]
|
|
2837
|
+
},
|
|
2838
|
+
color
|
|
2839
|
+
)) })
|
|
2840
|
+
] })
|
|
2803
2841
|
] }),
|
|
2804
2842
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native7.View, { style: s.bottomRow, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2805
2843
|
import_react_native7.TouchableOpacity,
|
|
@@ -3110,6 +3148,7 @@ var s = import_react_native7.StyleSheet.create({
|
|
|
3110
3148
|
styleScroll: { paddingHorizontal: 24, marginTop: 4 },
|
|
3111
3149
|
styleThumbWrap: { borderWidth: 2, borderRadius: 12, padding: 3, marginRight: 10 },
|
|
3112
3150
|
styleThumb: { width: 52, height: 52, borderRadius: 10, backgroundColor: "#E5E5EA" },
|
|
3151
|
+
colorSwatch: { width: 32, height: 32, borderRadius: 16, borderWidth: 1.5, borderColor: "rgba(255,255,255,0.15)", marginRight: 10 },
|
|
3113
3152
|
// Input
|
|
3114
3153
|
inputGroup: { paddingHorizontal: 24, gap: 6 },
|
|
3115
3154
|
inputLabel: { fontSize: 15, fontWeight: "600" },
|
|
@@ -3336,14 +3375,6 @@ function useAppConfig() {
|
|
|
3336
3375
|
// src/ui/UserProfileCard.tsx
|
|
3337
3376
|
var import_react19 = require("react");
|
|
3338
3377
|
var import_react_native8 = require("react-native");
|
|
3339
|
-
|
|
3340
|
-
// src/utils/avatarUrl.ts
|
|
3341
|
-
function ensurePngAvatar(url) {
|
|
3342
|
-
if (!url) return void 0;
|
|
3343
|
-
return url.replace("/svg?", "/png?");
|
|
3344
|
-
}
|
|
3345
|
-
|
|
3346
|
-
// src/ui/UserProfileCard.tsx
|
|
3347
3378
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
3348
3379
|
function truncateAddress(address, chars = 4) {
|
|
3349
3380
|
if (address.length <= chars * 2 + 3) return address;
|
|
@@ -3566,20 +3597,35 @@ var DICEBEAR_STYLES2 = [
|
|
|
3566
3597
|
"big-smile",
|
|
3567
3598
|
"thumbs"
|
|
3568
3599
|
];
|
|
3600
|
+
var BG_COLORS2 = [
|
|
3601
|
+
"1a1a2e",
|
|
3602
|
+
"f43f5e",
|
|
3603
|
+
"f97316",
|
|
3604
|
+
"eab308",
|
|
3605
|
+
"22c55e",
|
|
3606
|
+
"3b82f6",
|
|
3607
|
+
"8b5cf6",
|
|
3608
|
+
"ec4899",
|
|
3609
|
+
"06b6d4",
|
|
3610
|
+
"64748b"
|
|
3611
|
+
];
|
|
3569
3612
|
function generateSeed2() {
|
|
3570
3613
|
return Math.random().toString(36).slice(2, 10);
|
|
3571
3614
|
}
|
|
3572
|
-
function getAvatarUrl2(style, seed, size = 256) {
|
|
3573
|
-
return `https://api.dicebear.com/9.x/${style}/png?seed=${seed}&size=${size}`;
|
|
3615
|
+
function getAvatarUrl2(style, seed, bg = "1a1a2e", size = 256) {
|
|
3616
|
+
return `https://api.dicebear.com/9.x/${style}/png?seed=${seed}&backgroundColor=${bg}&size=${size}`;
|
|
3574
3617
|
}
|
|
3575
3618
|
function parseAvatarUrl(url) {
|
|
3576
|
-
if (!url) return { style: "adventurer", seed: generateSeed2() };
|
|
3619
|
+
if (!url) return { style: "adventurer", seed: generateSeed2(), bg: "1a1a2e" };
|
|
3577
3620
|
try {
|
|
3578
3621
|
const match = url.match(/\/\d+\.x\/([^/]+)\/(?:png|svg)\?seed=([^&]+)/);
|
|
3579
|
-
if (match)
|
|
3622
|
+
if (match) {
|
|
3623
|
+
const bgMatch = url.match(/backgroundColor=([^&]+)/);
|
|
3624
|
+
return { style: match[1], seed: match[2], bg: bgMatch?.[1] || "1a1a2e" };
|
|
3625
|
+
}
|
|
3580
3626
|
} catch {
|
|
3581
3627
|
}
|
|
3582
|
-
return { style: "adventurer", seed: generateSeed2() };
|
|
3628
|
+
return { style: "adventurer", seed: generateSeed2(), bg: "1a1a2e" };
|
|
3583
3629
|
}
|
|
3584
3630
|
function truncateAddress3(address, chars = 4) {
|
|
3585
3631
|
if (address.length <= chars * 2 + 3) return address;
|
|
@@ -3599,12 +3645,14 @@ function UserProfileSheet({
|
|
|
3599
3645
|
const parsed = (0, import_react20.useMemo)(() => parseAvatarUrl(user.avatar), [user.avatar]);
|
|
3600
3646
|
const [avatarStyle, setAvatarStyle] = (0, import_react20.useState)(parsed.style);
|
|
3601
3647
|
const [avatarSeed, setAvatarSeed] = (0, import_react20.useState)(parsed.seed);
|
|
3648
|
+
const [bgColor, setBgColor] = (0, import_react20.useState)(parsed.bg);
|
|
3602
3649
|
const [saving, setSaving] = (0, import_react20.useState)(false);
|
|
3603
3650
|
const [error, setError] = (0, import_react20.useState)(null);
|
|
3604
3651
|
(0, import_react20.useEffect)(() => {
|
|
3605
3652
|
const p = parseAvatarUrl(user.avatar);
|
|
3606
3653
|
setAvatarStyle(p.style);
|
|
3607
3654
|
setAvatarSeed(p.seed);
|
|
3655
|
+
setBgColor(p.bg);
|
|
3608
3656
|
}, [user.avatar]);
|
|
3609
3657
|
(0, import_react20.useEffect)(() => {
|
|
3610
3658
|
import_react_native10.Animated.timing(overlayOpacity, {
|
|
@@ -3616,28 +3664,8 @@ function UserProfileSheet({
|
|
|
3616
3664
|
(0, import_react20.useEffect)(() => {
|
|
3617
3665
|
if (visible) setError(null);
|
|
3618
3666
|
}, [visible]);
|
|
3619
|
-
const currentAvatarUrl = getAvatarUrl2(avatarStyle, avatarSeed);
|
|
3620
|
-
const
|
|
3621
|
-
async (style) => {
|
|
3622
|
-
const newUrl = getAvatarUrl2(style, avatarSeed);
|
|
3623
|
-
setAvatarStyle(style);
|
|
3624
|
-
setSaving(true);
|
|
3625
|
-
setError(null);
|
|
3626
|
-
try {
|
|
3627
|
-
await client.updateProfile({ avatar: newUrl });
|
|
3628
|
-
onAvatarUpdated?.(newUrl);
|
|
3629
|
-
} catch (err) {
|
|
3630
|
-
setError(err instanceof Error ? err.message : "Failed to update avatar");
|
|
3631
|
-
} finally {
|
|
3632
|
-
setSaving(false);
|
|
3633
|
-
}
|
|
3634
|
-
},
|
|
3635
|
-
[avatarSeed, client, onAvatarUpdated]
|
|
3636
|
-
);
|
|
3637
|
-
const handleShuffle = (0, import_react20.useCallback)(async () => {
|
|
3638
|
-
const newSeed = generateSeed2();
|
|
3639
|
-
const newUrl = getAvatarUrl2(avatarStyle, newSeed);
|
|
3640
|
-
setAvatarSeed(newSeed);
|
|
3667
|
+
const currentAvatarUrl = getAvatarUrl2(avatarStyle, avatarSeed, bgColor);
|
|
3668
|
+
const saveAvatar = (0, import_react20.useCallback)(async (newUrl) => {
|
|
3641
3669
|
setSaving(true);
|
|
3642
3670
|
setError(null);
|
|
3643
3671
|
try {
|
|
@@ -3648,7 +3676,26 @@ function UserProfileSheet({
|
|
|
3648
3676
|
} finally {
|
|
3649
3677
|
setSaving(false);
|
|
3650
3678
|
}
|
|
3651
|
-
}, [
|
|
3679
|
+
}, [client, onAvatarUpdated]);
|
|
3680
|
+
const handleSelectStyle = (0, import_react20.useCallback)(
|
|
3681
|
+
(style) => {
|
|
3682
|
+
setAvatarStyle(style);
|
|
3683
|
+
saveAvatar(getAvatarUrl2(style, avatarSeed, bgColor));
|
|
3684
|
+
},
|
|
3685
|
+
[avatarSeed, bgColor, saveAvatar]
|
|
3686
|
+
);
|
|
3687
|
+
const handleShuffle = (0, import_react20.useCallback)(() => {
|
|
3688
|
+
const newSeed = generateSeed2();
|
|
3689
|
+
setAvatarSeed(newSeed);
|
|
3690
|
+
saveAvatar(getAvatarUrl2(avatarStyle, newSeed, bgColor));
|
|
3691
|
+
}, [avatarStyle, bgColor, saveAvatar]);
|
|
3692
|
+
const handleSelectBgColor = (0, import_react20.useCallback)(
|
|
3693
|
+
(color) => {
|
|
3694
|
+
setBgColor(color);
|
|
3695
|
+
saveAvatar(getAvatarUrl2(avatarStyle, avatarSeed, color));
|
|
3696
|
+
},
|
|
3697
|
+
[avatarStyle, avatarSeed, saveAvatar]
|
|
3698
|
+
);
|
|
3652
3699
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
3653
3700
|
import_react_native10.Modal,
|
|
3654
3701
|
{
|
|
@@ -3729,7 +3776,7 @@ function UserProfileSheet({
|
|
|
3729
3776
|
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3730
3777
|
import_react_native10.Image,
|
|
3731
3778
|
{
|
|
3732
|
-
source: { uri: getAvatarUrl2(style, avatarSeed, 80) },
|
|
3779
|
+
source: { uri: getAvatarUrl2(style, avatarSeed, bgColor, 80) },
|
|
3733
3780
|
style: styles4.styleTileImage
|
|
3734
3781
|
}
|
|
3735
3782
|
)
|
|
@@ -3738,6 +3785,32 @@ function UserProfileSheet({
|
|
|
3738
3785
|
);
|
|
3739
3786
|
})
|
|
3740
3787
|
}
|
|
3788
|
+
),
|
|
3789
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native10.Text, { style: [styles4.sectionLabel, { color: t.textSecondary, marginTop: 4 }], children: "Background Color" }),
|
|
3790
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3791
|
+
import_react_native10.ScrollView,
|
|
3792
|
+
{
|
|
3793
|
+
horizontal: true,
|
|
3794
|
+
showsHorizontalScrollIndicator: false,
|
|
3795
|
+
contentContainerStyle: styles4.colorPickerContent,
|
|
3796
|
+
children: BG_COLORS2.map((color) => {
|
|
3797
|
+
const isSelected = color === bgColor;
|
|
3798
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3799
|
+
import_react_native10.TouchableOpacity,
|
|
3800
|
+
{
|
|
3801
|
+
onPress: () => handleSelectBgColor(color),
|
|
3802
|
+
activeOpacity: 0.7,
|
|
3803
|
+
disabled: saving,
|
|
3804
|
+
style: [
|
|
3805
|
+
styles4.colorSwatch,
|
|
3806
|
+
{ backgroundColor: `#${color}` },
|
|
3807
|
+
isSelected && { borderColor: t.accent, borderWidth: 2.5 }
|
|
3808
|
+
]
|
|
3809
|
+
},
|
|
3810
|
+
color
|
|
3811
|
+
);
|
|
3812
|
+
})
|
|
3813
|
+
}
|
|
3741
3814
|
)
|
|
3742
3815
|
] }),
|
|
3743
3816
|
error ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native10.View, { style: [styles4.errorBox, { backgroundColor: t.errorBg, borderColor: t.errorBorder }], children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native10.Text, { style: [styles4.errorText, { color: t.errorText }], children: error }) }) : null,
|
|
@@ -3899,6 +3972,16 @@ var styles4 = import_react_native10.StyleSheet.create({
|
|
|
3899
3972
|
stylePickerContent: {
|
|
3900
3973
|
gap: 10
|
|
3901
3974
|
},
|
|
3975
|
+
colorPickerContent: {
|
|
3976
|
+
gap: 8
|
|
3977
|
+
},
|
|
3978
|
+
colorSwatch: {
|
|
3979
|
+
width: 32,
|
|
3980
|
+
height: 32,
|
|
3981
|
+
borderRadius: 16,
|
|
3982
|
+
borderWidth: 1.5,
|
|
3983
|
+
borderColor: "rgba(255,255,255,0.15)"
|
|
3984
|
+
},
|
|
3902
3985
|
styleTile: {
|
|
3903
3986
|
width: 72,
|
|
3904
3987
|
height: 72,
|