@entropy-softworks/ui 2026.9.11 → 2026.910.2

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.
Files changed (78) hide show
  1. package/README.md +2 -2
  2. package/lib/components/error-boundary.d.ts.map +1 -1
  3. package/lib/components/error-boundary.jsx +3 -1
  4. package/lib/components/error-boundary.jsx.map +1 -1
  5. package/lib/components/index.d.ts +1 -1
  6. package/lib/components/index.d.ts.map +1 -1
  7. package/lib/components/index.js +1 -1
  8. package/lib/components/index.js.map +1 -1
  9. package/lib/components/password-generator.d.ts.map +1 -1
  10. package/lib/components/password-generator.jsx +15 -5
  11. package/lib/components/password-generator.jsx.map +1 -1
  12. package/lib/components/settings-row.d.ts.map +1 -1
  13. package/lib/components/settings-row.jsx +3 -1
  14. package/lib/components/settings-row.jsx.map +1 -1
  15. package/lib/components/social-connections.d.ts +52 -1
  16. package/lib/components/social-connections.d.ts.map +1 -1
  17. package/lib/components/social-connections.jsx +31 -2
  18. package/lib/components/social-connections.jsx.map +1 -1
  19. package/lib/hooks/usePasswordGenerator.d.ts.map +1 -1
  20. package/lib/hooks/usePasswordGenerator.js +1 -1
  21. package/lib/hooks/usePasswordGenerator.js.map +1 -1
  22. package/lib/screens/auth/AccountPickerScreen.d.ts.map +1 -1
  23. package/lib/screens/auth/AccountPickerScreen.jsx +1 -3
  24. package/lib/screens/auth/AccountPickerScreen.jsx.map +1 -1
  25. package/lib/screens/auth/AuthScreen.d.ts +8 -3
  26. package/lib/screens/auth/AuthScreen.d.ts.map +1 -1
  27. package/lib/screens/auth/AuthScreen.jsx +29 -14
  28. package/lib/screens/auth/AuthScreen.jsx.map +1 -1
  29. package/lib/screens/auth/ConsentScreen.jsx.map +1 -1
  30. package/lib/screens/auth/ErrorScreen.jsx.map +1 -1
  31. package/lib/screens/auth/ExpiredLinkScreen.d.ts.map +1 -1
  32. package/lib/screens/auth/ExpiredLinkScreen.jsx +1 -1
  33. package/lib/screens/auth/ExpiredLinkScreen.jsx.map +1 -1
  34. package/lib/screens/auth/ForgotPasswordScreen.d.ts.map +1 -1
  35. package/lib/screens/auth/ForgotPasswordScreen.jsx.map +1 -1
  36. package/lib/screens/auth/ImportDataScreen.jsx.map +1 -1
  37. package/lib/screens/auth/LoginScreen.d.ts.map +1 -1
  38. package/lib/screens/auth/LoginScreen.jsx.map +1 -1
  39. package/lib/screens/auth/MfaChallengeScreen.d.ts.map +1 -1
  40. package/lib/screens/auth/MfaChallengeScreen.jsx.map +1 -1
  41. package/lib/screens/auth/PasskeyEnrollScreen.d.ts.map +1 -1
  42. package/lib/screens/auth/PasskeyEnrollScreen.jsx +3 -5
  43. package/lib/screens/auth/PasskeyEnrollScreen.jsx.map +1 -1
  44. package/lib/screens/auth/PrivacyPolicyScreen.d.ts.map +1 -1
  45. package/lib/screens/auth/PrivacyPolicyScreen.jsx.map +1 -1
  46. package/lib/screens/auth/ResetPasswordScreen.d.ts.map +1 -1
  47. package/lib/screens/auth/ResetPasswordScreen.jsx.map +1 -1
  48. package/lib/screens/auth/ServerConfigScreen.d.ts.map +1 -1
  49. package/lib/screens/auth/ServerConfigScreen.jsx +15 -5
  50. package/lib/screens/auth/ServerConfigScreen.jsx.map +1 -1
  51. package/lib/screens/auth/TermsOfServiceScreen.d.ts.map +1 -1
  52. package/lib/screens/auth/TermsOfServiceScreen.jsx.map +1 -1
  53. package/lib/screens/auth/WelcomeScreen.d.ts.map +1 -1
  54. package/lib/screens/auth/WelcomeScreen.jsx.map +1 -1
  55. package/package.json +1 -1
  56. package/src/components/__tests__/social-connections.test.ts +97 -0
  57. package/src/components/error-boundary.tsx +3 -1
  58. package/src/components/index.ts +8 -1
  59. package/src/components/password-generator.tsx +15 -5
  60. package/src/components/settings-row.tsx +3 -1
  61. package/src/components/social-connections.tsx +68 -3
  62. package/src/hooks/usePasswordGenerator.ts +8 -1
  63. package/src/screens/auth/AccountPickerScreen.tsx +2 -4
  64. package/src/screens/auth/AuthScreen.tsx +41 -21
  65. package/src/screens/auth/ConsentScreen.tsx +2 -2
  66. package/src/screens/auth/ErrorScreen.tsx +2 -2
  67. package/src/screens/auth/ExpiredLinkScreen.tsx +3 -9
  68. package/src/screens/auth/ForgotPasswordScreen.tsx +6 -4
  69. package/src/screens/auth/ImportDataScreen.tsx +1 -1
  70. package/src/screens/auth/LoginScreen.tsx +13 -6
  71. package/src/screens/auth/MfaChallengeScreen.tsx +4 -1
  72. package/src/screens/auth/PasskeyEnrollScreen.tsx +5 -7
  73. package/src/screens/auth/PrivacyPolicyScreen.tsx +9 -3
  74. package/src/screens/auth/ResetPasswordScreen.tsx +6 -4
  75. package/src/screens/auth/ServerConfigScreen.tsx +19 -6
  76. package/src/screens/auth/TermsOfServiceScreen.tsx +9 -3
  77. package/src/screens/auth/WelcomeScreen.tsx +11 -4
  78. package/src/services/telemetry.ts +3 -3
@@ -4,13 +4,7 @@ import { SafeAreaView } from "react-native-safe-area-context";
4
4
  import { StatusBar } from "expo-status-bar";
5
5
  import { useColorScheme } from "nativewind";
6
6
  import { Button } from "../../components/button";
7
- import {
8
- Card,
9
- CardDescription,
10
- CardFooter,
11
- CardHeader,
12
- CardTitle,
13
- } from "../../components/card";
7
+ import { Card, CardDescription, CardFooter, CardHeader, CardTitle } from "../../components/card";
14
8
 
15
9
  export interface ExpiredLinkScreenProps {
16
10
  title?: string;
@@ -59,7 +53,7 @@ export function ExpiredLinkScreen({
59
53
  <Button
60
54
  className="w-full"
61
55
  telemetryId="auth.expired_link.request_new"
62
- onPress={onRequestNew}
56
+ onPress={onRequestNew}
63
57
  accessibilityLabel={requestLabel}
64
58
  accessibilityRole="button"
65
59
  >
@@ -71,7 +65,7 @@ export function ExpiredLinkScreen({
71
65
  className="w-full"
72
66
  variant="outline"
73
67
  telemetryId="auth.expired_link.home"
74
- onPress={onHome}
68
+ onPress={onHome}
75
69
  accessibilityLabel={homeLabel}
76
70
  accessibilityRole="button"
77
71
  >
@@ -81,7 +81,7 @@ export function ForgotPasswordScreen() {
81
81
  <IconButton
82
82
  variant="ghost"
83
83
  telemetryId="auth.forgot_password.back"
84
- onPress={() => router.back()}
84
+ onPress={() => router.back()}
85
85
  accessibilityLabel="Go back"
86
86
  accessibilityRole="button"
87
87
  >
@@ -123,7 +123,7 @@ export function ForgotPasswordScreen() {
123
123
  <Button
124
124
  className="w-full"
125
125
  telemetryId="auth.forgot_password.submit"
126
- onPress={handleSubmit}
126
+ onPress={handleSubmit}
127
127
  isLoading={isLoading}
128
128
  accessibilityLabel="Reset your password"
129
129
  accessibilityRole="button"
@@ -135,7 +135,9 @@ export function ForgotPasswordScreen() {
135
135
  Remember your password?{" "}
136
136
  <Text
137
137
  className="text-sm text-foreground underline"
138
- onPress={withClickTracking("auth.forgot_password.push", () => router.push(routes.login))}
138
+ onPress={withClickTracking("auth.forgot_password.push", () =>
139
+ router.push(routes.login)
140
+ )}
139
141
  accessibilityRole="link"
140
142
  accessibilityLabel="Sign in"
141
143
  >
@@ -149,7 +151,7 @@ export function ForgotPasswordScreen() {
149
151
  <Button
150
152
  className="w-full"
151
153
  telemetryId="auth.forgot_password.push_2"
152
- onPress={() =>
154
+ onPress={() =>
153
155
  router.push({
154
156
  pathname: routes.resetPassword,
155
157
  params: { email },
@@ -96,7 +96,7 @@ export function ImportDataScreen({ renderImport }: ImportDataScreenProps = {}) {
96
96
  <Button
97
97
  className="w-full"
98
98
  telemetryId="auth.import_data.complete_and_navigate"
99
- onPress={completeAndNavigate}
99
+ onPress={completeAndNavigate}
100
100
  accessibilityLabel={`Continue to ${appName}`}
101
101
  accessibilityRole="button"
102
102
  testID="import-continue"
@@ -282,7 +282,7 @@ export function LoginScreen({
282
282
  <IconButton
283
283
  variant="ghost"
284
284
  telemetryId="auth.login.push"
285
- onPress={() => router.push(routes.welcome)}
285
+ onPress={() => router.push(routes.welcome)}
286
286
  className="self-start"
287
287
  accessibilityLabel="Go back"
288
288
  accessibilityRole="button"
@@ -318,7 +318,7 @@ export function LoginScreen({
318
318
  variant="outline"
319
319
  className="w-full"
320
320
  telemetryId="auth.login.passkey_login"
321
- onPress={handlePasskeyLogin}
321
+ onPress={handlePasskeyLogin}
322
322
  isLoading={passkeyStep === "passkey-loading"}
323
323
  accessibilityLabel="Sign in with passkey"
324
324
  accessibilityRole="button"
@@ -378,7 +378,9 @@ export function LoginScreen({
378
378
  <View className="items-end">
379
379
  <Text
380
380
  className="font-mono text-sm underline"
381
- onPress={withClickTracking("auth.login.push_2", () => router.push(routes.forgotPassword))}
381
+ onPress={withClickTracking("auth.login.push_2", () =>
382
+ router.push(routes.forgotPassword)
383
+ )}
382
384
  accessibilityRole="link"
383
385
  accessibilityLabel="Forgot password"
384
386
  >
@@ -392,7 +394,9 @@ export function LoginScreen({
392
394
  Don&apos;t have an account?{" "}
393
395
  <Text
394
396
  className="text-sm text-foreground underline"
395
- onPress={withClickTracking("auth.login.push_3", () => router.push(routes.register))}
397
+ onPress={withClickTracking("auth.login.push_3", () =>
398
+ router.push(routes.register)
399
+ )}
396
400
  accessibilityRole="link"
397
401
  accessibilityLabel="Sign up"
398
402
  >
@@ -405,7 +409,7 @@ export function LoginScreen({
405
409
  <Button
406
410
  className="w-full"
407
411
  telemetryId="auth.login.login"
408
- onPress={handleLogin}
412
+ onPress={handleLogin}
409
413
  isLoading={isLoading}
410
414
  accessibilityLabel="Sign in"
411
415
  accessibilityRole="button"
@@ -473,7 +477,10 @@ export function LoginScreen({
473
477
  <DialogFooter style={{ justifyContent: "center" }}>
474
478
  <DialogButton
475
479
  variant="primary"
476
- onPress={withClickTracking("auth.login.action", isLoading ? () => {} : handleUnlockAfterPasskey)}
480
+ onPress={withClickTracking(
481
+ "auth.login.action",
482
+ isLoading ? () => {} : handleUnlockAfterPasskey
483
+ )}
477
484
  accessibilityLabel="Unlock"
478
485
  accessibilityRole="button"
479
486
  >
@@ -195,7 +195,10 @@ export function MfaChallengeScreen() {
195
195
  </Pressable>
196
196
 
197
197
  <Pressable
198
- onPress={withClickTracking("auth.mfa_challenge.toggle_recovery_mode", toggleRecoveryMode)}
198
+ onPress={withClickTracking(
199
+ "auth.mfa_challenge.toggle_recovery_mode",
200
+ toggleRecoveryMode
201
+ )}
199
202
  className="mt-5 items-center"
200
203
  hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
201
204
  accessibilityRole="button"
@@ -50,9 +50,8 @@ export function PasskeyEnrollScreen({
50
50
  <CardHeader>
51
51
  <CardTitle>Add a passkey</CardTitle>
52
52
  <CardDescription>
53
- Sign in faster and more securely next time with a passkey — your
54
- device unlocks it with your fingerprint, face, or PIN. No password
55
- to remember or phish.
53
+ Sign in faster and more securely next time with a passkey — your device unlocks it
54
+ with your fingerprint, face, or PIN. No password to remember or phish.
56
55
  </CardDescription>
57
56
  </CardHeader>
58
57
 
@@ -61,8 +60,7 @@ export function PasskeyEnrollScreen({
61
60
  <Text className="text-sm text-destructive dark:text-red-900">{error}</Text>
62
61
  ) : (
63
62
  <MutedText className="text-sm">
64
- You can always add or remove passkeys later in your account
65
- settings.
63
+ You can always add or remove passkeys later in your account settings.
66
64
  </MutedText>
67
65
  )}
68
66
  </CardContent>
@@ -71,7 +69,7 @@ export function PasskeyEnrollScreen({
71
69
  <Button
72
70
  className="w-full"
73
71
  telemetryId="auth.passkey_enroll.enroll"
74
- onPress={onEnroll}
72
+ onPress={onEnroll}
75
73
  isLoading={isLoading}
76
74
  accessibilityLabel="Add a passkey"
77
75
  accessibilityRole="button"
@@ -82,7 +80,7 @@ export function PasskeyEnrollScreen({
82
80
  className="w-full"
83
81
  variant="ghost"
84
82
  telemetryId="auth.passkey_enroll.skip"
85
- onPress={onSkip}
83
+ onPress={onSkip}
86
84
  accessibilityLabel="Not now"
87
85
  accessibilityRole="button"
88
86
  >
@@ -62,8 +62,12 @@ export function PrivacyPolicyScreen({
62
62
  <View className="flex-1" style={{ backgroundColor: isDark ? "#000000" : "#FFFFFF" }}>
63
63
  <View className="px-6 pt-4 pb-6">
64
64
  <View className="flex-row items-center justify-between mb-6">
65
- <IconButton variant="ghost" size="sm" telemetryId="auth.privacy_policy.back"
66
- onPress={() => router.back()}>
65
+ <IconButton
66
+ variant="ghost"
67
+ size="sm"
68
+ telemetryId="auth.privacy_policy.back"
69
+ onPress={() => router.back()}
70
+ >
67
71
  <Ionicons name="arrow-back" size={20} color={isDark ? "#FFFFFF" : "#000000"} />
68
72
  </IconButton>
69
73
 
@@ -191,7 +195,9 @@ export function PrivacyPolicyScreen({
191
195
  <Text
192
196
  className="font-mono text-sm underline"
193
197
  style={{ color: isDark ? "#6BA3E5" : "#4A90E2" }}
194
- onPress={withClickTracking("auth.privacy_policy.open_u_r_l", () => Linking.openURL(`mailto:${supportEmail}`))}
198
+ onPress={withClickTracking("auth.privacy_policy.open_u_r_l", () =>
199
+ Linking.openURL(`mailto:${supportEmail}`)
200
+ )}
195
201
  >
196
202
  {supportEmail}
197
203
  </Text>
@@ -230,7 +230,7 @@ export function ResetPasswordScreen({ encryptionWarning }: ResetPasswordScreenPr
230
230
  <IconButton
231
231
  variant="ghost"
232
232
  telemetryId="auth.reset_password.step"
233
- onPress={() => (step === "password" ? setStep("code") : router.back())}
233
+ onPress={() => (step === "password" ? setStep("code") : router.back())}
234
234
  accessibilityLabel="Go back"
235
235
  accessibilityRole="button"
236
236
  >
@@ -273,7 +273,7 @@ export function ResetPasswordScreen({ encryptionWarning }: ResetPasswordScreenPr
273
273
  <Button
274
274
  className="w-full"
275
275
  telemetryId="auth.reset_password.code_submit"
276
- onPress={handleCodeSubmit}
276
+ onPress={handleCodeSubmit}
277
277
  isLoading={isLoading}
278
278
  accessibilityLabel="Continue"
279
279
  accessibilityRole="button"
@@ -285,7 +285,9 @@ export function ResetPasswordScreen({ encryptionWarning }: ResetPasswordScreenPr
285
285
  Back to{" "}
286
286
  <Text
287
287
  className="text-sm text-foreground underline"
288
- onPress={withClickTracking("auth.reset_password.push", () => router.push(routes.login))}
288
+ onPress={withClickTracking("auth.reset_password.push", () =>
289
+ router.push(routes.login)
290
+ )}
289
291
  accessibilityRole="link"
290
292
  accessibilityLabel="Sign in"
291
293
  >
@@ -351,7 +353,7 @@ export function ResetPasswordScreen({ encryptionWarning }: ResetPasswordScreenPr
351
353
  <Button
352
354
  className="w-full"
353
355
  telemetryId="auth.reset_password.password_submit"
354
- onPress={handlePasswordSubmit}
356
+ onPress={handlePasswordSubmit}
355
357
  isLoading={isLoading}
356
358
  accessibilityLabel="Reset password"
357
359
  accessibilityRole="button"
@@ -251,7 +251,9 @@ export function ServerConfigScreen({
251
251
  >
252
252
  <Ionicons name="close" size={24} color={isDark ? "white" : "black"} />
253
253
  </Pressable>
254
- <Text className="text-lg font-semibold text-foreground dark:text-white">Server Configuration</Text>
254
+ <Text className="text-lg font-semibold text-foreground dark:text-white">
255
+ Server Configuration
256
+ </Text>
255
257
  <View className="h-10 w-10" />
256
258
  </View>
257
259
 
@@ -275,7 +277,9 @@ export function ServerConfigScreen({
275
277
  </View>
276
278
 
277
279
  <View className="mb-6">
278
- <Text className="mb-2 text-sm font-medium text-foreground dark:text-white">Server URL</Text>
280
+ <Text className="mb-2 text-sm font-medium text-foreground dark:text-white">
281
+ Server URL
282
+ </Text>
279
283
  <View className="flex-row items-center rounded-lg border border-border dark:border-neutral-800 bg-background dark:bg-black px-3 py-3">
280
284
  <Ionicons
281
285
  name="globe-outline"
@@ -345,7 +349,10 @@ export function ServerConfigScreen({
345
349
  </Pressable>
346
350
 
347
351
  <Pressable
348
- onPress={withClickTracking("auth.server_config.clear_configuration", handleClearConfiguration)}
352
+ onPress={withClickTracking(
353
+ "auth.server_config.clear_configuration",
354
+ handleClearConfiguration
355
+ )}
349
356
  accessibilityRole="button"
350
357
  accessibilityLabel="Clear all settings"
351
358
  className="active:scale-98 mb-3 w-full rounded-lg border border-destructive dark:border-red-900 bg-background dark:bg-black px-6 py-3"
@@ -370,12 +377,18 @@ export function ServerConfigScreen({
370
377
  </Pressable>
371
378
 
372
379
  <View className="rounded-lg bg-card dark:bg-neutral-900/50 p-4">
373
- <Text className="mb-3 text-sm font-semibold text-foreground dark:text-white">Need Help?</Text>
380
+ <Text className="mb-3 text-sm font-semibold text-foreground dark:text-white">
381
+ Need Help?
382
+ </Text>
374
383
  <View className="space-y-2">
375
384
  {bullets.map((bullet, idx) => (
376
385
  <View key={idx} className="flex-row items-start">
377
- <Text className="mr-2 text-sm text-muted-foreground dark:text-neutral-400">•</Text>
378
- <Text className="flex-1 text-sm text-muted-foreground dark:text-neutral-400">{bullet}</Text>
386
+ <Text className="mr-2 text-sm text-muted-foreground dark:text-neutral-400">
387
+
388
+ </Text>
389
+ <Text className="flex-1 text-sm text-muted-foreground dark:text-neutral-400">
390
+ {bullet}
391
+ </Text>
379
392
  </View>
380
393
  ))}
381
394
  </View>
@@ -74,8 +74,12 @@ export function TermsOfServiceScreen({
74
74
  <View className="flex-1" style={{ backgroundColor: isDark ? "#000000" : "#FFFFFF" }}>
75
75
  <View className="px-6 pt-4 pb-6">
76
76
  <View className="flex-row items-center justify-between mb-6">
77
- <IconButton variant="ghost" size="sm" telemetryId="auth.terms_of_service.back"
78
- onPress={() => router.back()}>
77
+ <IconButton
78
+ variant="ghost"
79
+ size="sm"
80
+ telemetryId="auth.terms_of_service.back"
81
+ onPress={() => router.back()}
82
+ >
79
83
  <Ionicons name="arrow-back" size={20} color={isDark ? "#FFFFFF" : "#000000"} />
80
84
  </IconButton>
81
85
 
@@ -168,7 +172,9 @@ export function TermsOfServiceScreen({
168
172
  <Text
169
173
  className="font-mono text-sm underline"
170
174
  style={{ color: isDark ? "#6BA3E5" : "#4A90E2" }}
171
- onPress={withClickTracking("auth.terms_of_service.open_u_r_l", () => Linking.openURL(`mailto:${supportEmail}`))}
175
+ onPress={withClickTracking("auth.terms_of_service.open_u_r_l", () =>
176
+ Linking.openURL(`mailto:${supportEmail}`)
177
+ )}
172
178
  >
173
179
  {supportEmail}
174
180
  </Text>
@@ -50,12 +50,19 @@ export function WelcomeScreen({ decoration, topAccessory }: WelcomeScreenProps)
50
50
  ) : null}
51
51
 
52
52
  <View className="w-full max-w-[360px] gap-3">
53
- <Button className="w-full" telemetryId="auth.welcome.push"
54
- onPress={() => router.push(routes.login)}>
53
+ <Button
54
+ className="w-full"
55
+ telemetryId="auth.welcome.push"
56
+ onPress={() => router.push(routes.login)}
57
+ >
55
58
  Sign In
56
59
  </Button>
57
- <Button variant="outline" className="w-full" telemetryId="auth.welcome.push_2"
58
- onPress={() => router.push(routes.register)}>
60
+ <Button
61
+ variant="outline"
62
+ className="w-full"
63
+ telemetryId="auth.welcome.push_2"
64
+ onPress={() => router.push(routes.register)}
65
+ >
59
66
  Create Account
60
67
  </Button>
61
68
  </View>
@@ -70,11 +70,11 @@ export function trackClick(element: string, route?: string): void {
70
70
  */
71
71
  export function withClickTracking<F extends (...args: never[]) => unknown>(
72
72
  element: string | undefined,
73
- handler: F,
73
+ handler: F
74
74
  ): F;
75
75
  export function withClickTracking<F extends (...args: never[]) => unknown>(
76
76
  element: string | undefined,
77
- handler: F | null | undefined,
77
+ handler: F | null | undefined
78
78
  ): F | undefined;
79
79
  /**
80
80
  * Wrap a press handler so activating the element is reported first.
@@ -88,7 +88,7 @@ export function withClickTracking<F extends (...args: never[]) => unknown>(
88
88
  */
89
89
  export function withClickTracking(
90
90
  element: string | undefined,
91
- handler: ((...args: never[]) => unknown) | null | undefined,
91
+ handler: ((...args: never[]) => unknown) | null | undefined
92
92
  ): ((...args: never[]) => unknown) | undefined {
93
93
  // Untagged controls keep their original handler rather than gaining a
94
94
  // closure per render for nothing.