@oxyhq/services 22.9.0 → 22.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (584) hide show
  1. package/lib/commonjs/index.js +24 -5
  2. package/lib/commonjs/index.js.map +1 -1
  3. package/lib/commonjs/ui/components/AvatarCameraBadge.js +42 -0
  4. package/lib/commonjs/ui/components/AvatarCameraBadge.js.map +1 -0
  5. package/lib/commonjs/ui/components/{OxyAccountDialog.js → OxyAccountDialogScreen.js} +55 -133
  6. package/lib/commonjs/ui/components/OxyAccountDialogScreen.js.map +1 -0
  7. package/lib/commonjs/ui/components/OxyAuthChooser.js +657 -88
  8. package/lib/commonjs/ui/components/OxyAuthChooser.js.map +1 -1
  9. package/lib/commonjs/ui/components/OxyConsentScreen.js +1 -1
  10. package/lib/commonjs/ui/components/ProfileButton.js +15 -1
  11. package/lib/commonjs/ui/components/ProfileButton.js.map +1 -1
  12. package/lib/commonjs/ui/components/ProfileSummaryCard.js +3 -23
  13. package/lib/commonjs/ui/components/ProfileSummaryCard.js.map +1 -1
  14. package/lib/commonjs/ui/components/RequireOxyAuth.js +1 -1
  15. package/lib/commonjs/ui/components/SurfaceHeaderAction.js +63 -0
  16. package/lib/commonjs/ui/components/SurfaceHeaderAction.js.map +1 -0
  17. package/lib/commonjs/ui/components/SurfaceScreen.js +91 -8
  18. package/lib/commonjs/ui/components/SurfaceScreen.js.map +1 -1
  19. package/lib/commonjs/ui/components/fileManagement/FileDetailsModal.js +46 -29
  20. package/lib/commonjs/ui/components/fileManagement/FileDetailsModal.js.map +1 -1
  21. package/lib/commonjs/ui/components/modals/DeleteAccountModal.js +47 -23
  22. package/lib/commonjs/ui/components/modals/DeleteAccountModal.js.map +1 -1
  23. package/lib/commonjs/ui/components/oxyAuthChooserStyles.js +81 -19
  24. package/lib/commonjs/ui/components/oxyAuthChooserStyles.js.map +1 -1
  25. package/lib/commonjs/ui/components/photogrid/JustifiedPhotoGrid.js +83 -23
  26. package/lib/commonjs/ui/components/photogrid/JustifiedPhotoGrid.js.map +1 -1
  27. package/lib/commonjs/ui/components/surfaces/ActionSheetSurface.js +83 -0
  28. package/lib/commonjs/ui/components/surfaces/ActionSheetSurface.js.map +1 -0
  29. package/lib/commonjs/ui/context/OxyContext.js +79 -29
  30. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  31. package/lib/commonjs/ui/hooks/queries/queryKeys.js +18 -1
  32. package/lib/commonjs/ui/hooks/queries/queryKeys.js.map +1 -1
  33. package/lib/commonjs/ui/hooks/queries/useFileQueries.js +129 -0
  34. package/lib/commonjs/ui/hooks/queries/useFileQueries.js.map +1 -0
  35. package/lib/commonjs/ui/hooks/useAvatarPicker.js +38 -55
  36. package/lib/commonjs/ui/hooks/useAvatarPicker.js.map +1 -1
  37. package/lib/commonjs/ui/hooks/useReduceMotion.js +57 -0
  38. package/lib/commonjs/ui/hooks/useReduceMotion.js.map +1 -0
  39. package/lib/commonjs/ui/hooks/useSurfaceHeader.js +46 -0
  40. package/lib/commonjs/ui/hooks/useSurfaceHeader.js.map +1 -0
  41. package/lib/commonjs/ui/hooks/useSwitchableAccounts.js +1 -1
  42. package/lib/commonjs/ui/navigation/accountDialogManager.js +36 -2
  43. package/lib/commonjs/ui/navigation/accountDialogManager.js.map +1 -1
  44. package/lib/commonjs/ui/navigation/bottomSheetManager.js +5 -6
  45. package/lib/commonjs/ui/navigation/bottomSheetManager.js.map +1 -1
  46. package/lib/commonjs/ui/navigation/routes.js +4 -3
  47. package/lib/commonjs/ui/navigation/routes.js.map +1 -1
  48. package/lib/commonjs/ui/navigation/surfaceBackBridge.js +68 -0
  49. package/lib/commonjs/ui/navigation/surfaceBackBridge.js.map +1 -0
  50. package/lib/commonjs/ui/navigation/surfaceNavStack.js +62 -15
  51. package/lib/commonjs/ui/navigation/surfaceNavStack.js.map +1 -1
  52. package/lib/commonjs/ui/navigation/surfaceRegistry.js +84 -19
  53. package/lib/commonjs/ui/navigation/surfaceRegistry.js.map +1 -1
  54. package/lib/commonjs/ui/navigation/surfaces.js +139 -25
  55. package/lib/commonjs/ui/navigation/surfaces.js.map +1 -1
  56. package/lib/commonjs/ui/screens/AccountMembersScreen.js +214 -283
  57. package/lib/commonjs/ui/screens/AccountMembersScreen.js.map +1 -1
  58. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +88 -118
  59. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  60. package/lib/commonjs/ui/screens/AccountVerificationScreen.js +22 -36
  61. package/lib/commonjs/ui/screens/AccountVerificationScreen.js.map +1 -1
  62. package/lib/commonjs/ui/screens/AppInfoScreen.js +219 -226
  63. package/lib/commonjs/ui/screens/AppInfoScreen.js.map +1 -1
  64. package/lib/commonjs/ui/screens/AvatarCropScreen.js +287 -289
  65. package/lib/commonjs/ui/screens/AvatarCropScreen.js.map +1 -1
  66. package/lib/commonjs/ui/screens/ChangeAvatarScreen.js +301 -0
  67. package/lib/commonjs/ui/screens/ChangeAvatarScreen.js.map +1 -0
  68. package/lib/commonjs/ui/screens/ConnectedAppsScreen.js +24 -39
  69. package/lib/commonjs/ui/screens/ConnectedAppsScreen.js.map +1 -1
  70. package/lib/commonjs/ui/screens/CreateAccountScreen.js +136 -158
  71. package/lib/commonjs/ui/screens/CreateAccountScreen.js.map +1 -1
  72. package/lib/commonjs/ui/screens/EditProfileFieldScreen.js +29 -36
  73. package/lib/commonjs/ui/screens/EditProfileFieldScreen.js.map +1 -1
  74. package/lib/commonjs/ui/screens/EditProfileScreen.js +101 -109
  75. package/lib/commonjs/ui/screens/EditProfileScreen.js.map +1 -1
  76. package/lib/commonjs/ui/screens/FAQScreen.js +10 -15
  77. package/lib/commonjs/ui/screens/FAQScreen.js.map +1 -1
  78. package/lib/commonjs/ui/screens/FeedbackScreen.js +8 -16
  79. package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
  80. package/lib/commonjs/ui/screens/FileManagementScreen.js +403 -627
  81. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
  82. package/lib/commonjs/ui/screens/HelpSupportScreen.js +62 -69
  83. package/lib/commonjs/ui/screens/HelpSupportScreen.js.map +1 -1
  84. package/lib/commonjs/ui/screens/HistoryViewScreen.js +63 -79
  85. package/lib/commonjs/ui/screens/HistoryViewScreen.js.map +1 -1
  86. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +69 -98
  87. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -1
  88. package/lib/commonjs/ui/screens/LearnMoreUsernamesScreen.js +8 -14
  89. package/lib/commonjs/ui/screens/LearnMoreUsernamesScreen.js.map +1 -1
  90. package/lib/commonjs/ui/screens/LegalDocumentsScreen.js +77 -94
  91. package/lib/commonjs/ui/screens/LegalDocumentsScreen.js.map +1 -1
  92. package/lib/commonjs/ui/screens/ManageAccountScreen.js +99 -134
  93. package/lib/commonjs/ui/screens/ManageAccountScreen.js.map +1 -1
  94. package/lib/commonjs/ui/screens/NotificationsScreen.js +69 -76
  95. package/lib/commonjs/ui/screens/NotificationsScreen.js.map +1 -1
  96. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js +3 -8
  97. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js.map +1 -1
  98. package/lib/commonjs/ui/screens/PreferencesScreen.js +67 -74
  99. package/lib/commonjs/ui/screens/PreferencesScreen.js.map +1 -1
  100. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js +55 -91
  101. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
  102. package/lib/commonjs/ui/screens/PrivacySettingsScreen.js +291 -304
  103. package/lib/commonjs/ui/screens/PrivacySettingsScreen.js.map +1 -1
  104. package/lib/commonjs/ui/screens/ProfileScreen.js +100 -114
  105. package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
  106. package/lib/commonjs/ui/screens/SavesCollectionsScreen.js +38 -45
  107. package/lib/commonjs/ui/screens/SavesCollectionsScreen.js.map +1 -1
  108. package/lib/commonjs/ui/screens/SearchSettingsScreen.js +44 -57
  109. package/lib/commonjs/ui/screens/SearchSettingsScreen.js.map +1 -1
  110. package/lib/commonjs/ui/screens/UserLinksScreen.js +24 -31
  111. package/lib/commonjs/ui/screens/UserLinksScreen.js.map +1 -1
  112. package/lib/commonjs/ui/screens/UserListScreen.js +14 -24
  113. package/lib/commonjs/ui/screens/UserListScreen.js.map +1 -1
  114. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +16 -48
  115. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  116. package/lib/commonjs/ui/screens/fileManagement/FileLibraryError.js +63 -0
  117. package/lib/commonjs/ui/screens/fileManagement/FileLibraryError.js.map +1 -0
  118. package/lib/commonjs/ui/screens/fileManagement/PhotoPickerSection.js +54 -41
  119. package/lib/commonjs/ui/screens/fileManagement/PhotoPickerSection.js.map +1 -1
  120. package/lib/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.js +44 -81
  121. package/lib/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.js.map +1 -1
  122. package/lib/commonjs/ui/screens/trust/TrustAboutScreen.js +66 -75
  123. package/lib/commonjs/ui/screens/trust/TrustAboutScreen.js.map +1 -1
  124. package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js +111 -139
  125. package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js.map +1 -1
  126. package/lib/commonjs/ui/screens/trust/TrustFAQScreen.js +13 -20
  127. package/lib/commonjs/ui/screens/trust/TrustFAQScreen.js.map +1 -1
  128. package/lib/commonjs/ui/screens/trust/TrustLeaderboardScreen.js +14 -27
  129. package/lib/commonjs/ui/screens/trust/TrustLeaderboardScreen.js.map +1 -1
  130. package/lib/commonjs/ui/screens/trust/TrustRewardsScreen.js +68 -85
  131. package/lib/commonjs/ui/screens/trust/TrustRewardsScreen.js.map +1 -1
  132. package/lib/commonjs/ui/screens/trust/TrustRulesScreen.js +28 -36
  133. package/lib/commonjs/ui/screens/trust/TrustRulesScreen.js.map +1 -1
  134. package/lib/commonjs/ui/stores/resetSessionScopedStores.js +8 -3
  135. package/lib/commonjs/ui/stores/resetSessionScopedStores.js.map +1 -1
  136. package/lib/commonjs/ui/utils/avatarUtils.js +11 -2
  137. package/lib/commonjs/ui/utils/avatarUtils.js.map +1 -1
  138. package/lib/commonjs/ui/utils/fileManagement.js +0 -79
  139. package/lib/commonjs/ui/utils/fileManagement.js.map +1 -1
  140. package/lib/module/index.js +12 -5
  141. package/lib/module/index.js.map +1 -1
  142. package/lib/module/ui/components/AvatarCameraBadge.js +40 -0
  143. package/lib/module/ui/components/AvatarCameraBadge.js.map +1 -0
  144. package/lib/module/ui/components/{OxyAccountDialog.js → OxyAccountDialogScreen.js} +57 -135
  145. package/lib/module/ui/components/OxyAccountDialogScreen.js.map +1 -0
  146. package/lib/module/ui/components/OxyAuthChooser.js +659 -91
  147. package/lib/module/ui/components/OxyAuthChooser.js.map +1 -1
  148. package/lib/module/ui/components/OxyConsentScreen.js +1 -1
  149. package/lib/module/ui/components/ProfileButton.js +16 -2
  150. package/lib/module/ui/components/ProfileButton.js.map +1 -1
  151. package/lib/module/ui/components/ProfileSummaryCard.js +2 -23
  152. package/lib/module/ui/components/ProfileSummaryCard.js.map +1 -1
  153. package/lib/module/ui/components/RequireOxyAuth.js +1 -1
  154. package/lib/module/ui/components/SurfaceHeaderAction.js +58 -0
  155. package/lib/module/ui/components/SurfaceHeaderAction.js.map +1 -0
  156. package/lib/module/ui/components/SurfaceScreen.js +93 -10
  157. package/lib/module/ui/components/SurfaceScreen.js.map +1 -1
  158. package/lib/module/ui/components/fileManagement/FileDetailsModal.js +46 -29
  159. package/lib/module/ui/components/fileManagement/FileDetailsModal.js.map +1 -1
  160. package/lib/module/ui/components/modals/DeleteAccountModal.js +46 -23
  161. package/lib/module/ui/components/modals/DeleteAccountModal.js.map +1 -1
  162. package/lib/module/ui/components/oxyAuthChooserStyles.js +81 -19
  163. package/lib/module/ui/components/oxyAuthChooserStyles.js.map +1 -1
  164. package/lib/module/ui/components/photogrid/JustifiedPhotoGrid.js +83 -25
  165. package/lib/module/ui/components/photogrid/JustifiedPhotoGrid.js.map +1 -1
  166. package/lib/module/ui/components/surfaces/ActionSheetSurface.js +78 -0
  167. package/lib/module/ui/components/surfaces/ActionSheetSurface.js.map +1 -0
  168. package/lib/module/ui/context/OxyContext.js +80 -30
  169. package/lib/module/ui/context/OxyContext.js.map +1 -1
  170. package/lib/module/ui/hooks/queries/queryKeys.js +16 -0
  171. package/lib/module/ui/hooks/queries/queryKeys.js.map +1 -1
  172. package/lib/module/ui/hooks/queries/useFileQueries.js +120 -0
  173. package/lib/module/ui/hooks/queries/useFileQueries.js.map +1 -0
  174. package/lib/module/ui/hooks/useAvatarPicker.js +38 -55
  175. package/lib/module/ui/hooks/useAvatarPicker.js.map +1 -1
  176. package/lib/module/ui/hooks/useReduceMotion.js +53 -0
  177. package/lib/module/ui/hooks/useReduceMotion.js.map +1 -0
  178. package/lib/module/ui/hooks/useSurfaceHeader.js +42 -0
  179. package/lib/module/ui/hooks/useSurfaceHeader.js.map +1 -0
  180. package/lib/module/ui/hooks/useSwitchableAccounts.js +1 -1
  181. package/lib/module/ui/navigation/accountDialogManager.js +34 -2
  182. package/lib/module/ui/navigation/accountDialogManager.js.map +1 -1
  183. package/lib/module/ui/navigation/bottomSheetManager.js +6 -7
  184. package/lib/module/ui/navigation/bottomSheetManager.js.map +1 -1
  185. package/lib/module/ui/navigation/routes.js +4 -3
  186. package/lib/module/ui/navigation/routes.js.map +1 -1
  187. package/lib/module/ui/navigation/surfaceBackBridge.js +63 -0
  188. package/lib/module/ui/navigation/surfaceBackBridge.js.map +1 -0
  189. package/lib/module/ui/navigation/surfaceNavStack.js +62 -15
  190. package/lib/module/ui/navigation/surfaceNavStack.js.map +1 -1
  191. package/lib/module/ui/navigation/surfaceRegistry.js +84 -19
  192. package/lib/module/ui/navigation/surfaceRegistry.js.map +1 -1
  193. package/lib/module/ui/navigation/surfaces.js +138 -26
  194. package/lib/module/ui/navigation/surfaces.js.map +1 -1
  195. package/lib/module/ui/screens/AccountMembersScreen.js +218 -286
  196. package/lib/module/ui/screens/AccountMembersScreen.js.map +1 -1
  197. package/lib/module/ui/screens/AccountSettingsScreen.js +92 -121
  198. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  199. package/lib/module/ui/screens/AccountVerificationScreen.js +25 -38
  200. package/lib/module/ui/screens/AccountVerificationScreen.js.map +1 -1
  201. package/lib/module/ui/screens/AppInfoScreen.js +220 -227
  202. package/lib/module/ui/screens/AppInfoScreen.js.map +1 -1
  203. package/lib/module/ui/screens/AvatarCropScreen.js +289 -291
  204. package/lib/module/ui/screens/AvatarCropScreen.js.map +1 -1
  205. package/lib/module/ui/screens/ChangeAvatarScreen.js +298 -0
  206. package/lib/module/ui/screens/ChangeAvatarScreen.js.map +1 -0
  207. package/lib/module/ui/screens/ConnectedAppsScreen.js +26 -40
  208. package/lib/module/ui/screens/ConnectedAppsScreen.js.map +1 -1
  209. package/lib/module/ui/screens/CreateAccountScreen.js +139 -160
  210. package/lib/module/ui/screens/CreateAccountScreen.js.map +1 -1
  211. package/lib/module/ui/screens/EditProfileFieldScreen.js +32 -38
  212. package/lib/module/ui/screens/EditProfileFieldScreen.js.map +1 -1
  213. package/lib/module/ui/screens/EditProfileScreen.js +102 -110
  214. package/lib/module/ui/screens/EditProfileScreen.js.map +1 -1
  215. package/lib/module/ui/screens/FAQScreen.js +11 -15
  216. package/lib/module/ui/screens/FAQScreen.js.map +1 -1
  217. package/lib/module/ui/screens/FeedbackScreen.js +10 -17
  218. package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
  219. package/lib/module/ui/screens/FileManagementScreen.js +408 -631
  220. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
  221. package/lib/module/ui/screens/HelpSupportScreen.js +64 -70
  222. package/lib/module/ui/screens/HelpSupportScreen.js.map +1 -1
  223. package/lib/module/ui/screens/HistoryViewScreen.js +65 -81
  224. package/lib/module/ui/screens/HistoryViewScreen.js.map +1 -1
  225. package/lib/module/ui/screens/LanguageSelectorScreen.js +71 -99
  226. package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -1
  227. package/lib/module/ui/screens/LearnMoreUsernamesScreen.js +10 -15
  228. package/lib/module/ui/screens/LearnMoreUsernamesScreen.js.map +1 -1
  229. package/lib/module/ui/screens/LegalDocumentsScreen.js +78 -94
  230. package/lib/module/ui/screens/LegalDocumentsScreen.js.map +1 -1
  231. package/lib/module/ui/screens/ManageAccountScreen.js +102 -137
  232. package/lib/module/ui/screens/ManageAccountScreen.js.map +1 -1
  233. package/lib/module/ui/screens/NotificationsScreen.js +71 -77
  234. package/lib/module/ui/screens/NotificationsScreen.js.map +1 -1
  235. package/lib/module/ui/screens/PaymentGatewayScreen.js +4 -9
  236. package/lib/module/ui/screens/PaymentGatewayScreen.js.map +1 -1
  237. package/lib/module/ui/screens/PreferencesScreen.js +69 -75
  238. package/lib/module/ui/screens/PreferencesScreen.js.map +1 -1
  239. package/lib/module/ui/screens/PremiumSubscriptionScreen.js +58 -93
  240. package/lib/module/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
  241. package/lib/module/ui/screens/PrivacySettingsScreen.js +293 -305
  242. package/lib/module/ui/screens/PrivacySettingsScreen.js.map +1 -1
  243. package/lib/module/ui/screens/ProfileScreen.js +102 -116
  244. package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
  245. package/lib/module/ui/screens/SavesCollectionsScreen.js +40 -46
  246. package/lib/module/ui/screens/SavesCollectionsScreen.js.map +1 -1
  247. package/lib/module/ui/screens/SearchSettingsScreen.js +46 -58
  248. package/lib/module/ui/screens/SearchSettingsScreen.js.map +1 -1
  249. package/lib/module/ui/screens/UserLinksScreen.js +26 -32
  250. package/lib/module/ui/screens/UserLinksScreen.js.map +1 -1
  251. package/lib/module/ui/screens/UserListScreen.js +14 -24
  252. package/lib/module/ui/screens/UserListScreen.js.map +1 -1
  253. package/lib/module/ui/screens/WelcomeNewUserScreen.js +17 -49
  254. package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  255. package/lib/module/ui/screens/fileManagement/FileLibraryError.js +59 -0
  256. package/lib/module/ui/screens/fileManagement/FileLibraryError.js.map +1 -0
  257. package/lib/module/ui/screens/fileManagement/PhotoPickerSection.js +54 -42
  258. package/lib/module/ui/screens/fileManagement/PhotoPickerSection.js.map +1 -1
  259. package/lib/module/ui/screens/fileManagement/hooks/useFileUploadState.js +45 -81
  260. package/lib/module/ui/screens/fileManagement/hooks/useFileUploadState.js.map +1 -1
  261. package/lib/module/ui/screens/trust/TrustAboutScreen.js +67 -75
  262. package/lib/module/ui/screens/trust/TrustAboutScreen.js.map +1 -1
  263. package/lib/module/ui/screens/trust/TrustCenterScreen.js +112 -139
  264. package/lib/module/ui/screens/trust/TrustCenterScreen.js.map +1 -1
  265. package/lib/module/ui/screens/trust/TrustFAQScreen.js +15 -21
  266. package/lib/module/ui/screens/trust/TrustFAQScreen.js.map +1 -1
  267. package/lib/module/ui/screens/trust/TrustLeaderboardScreen.js +14 -26
  268. package/lib/module/ui/screens/trust/TrustLeaderboardScreen.js.map +1 -1
  269. package/lib/module/ui/screens/trust/TrustRewardsScreen.js +69 -85
  270. package/lib/module/ui/screens/trust/TrustRewardsScreen.js.map +1 -1
  271. package/lib/module/ui/screens/trust/TrustRulesScreen.js +30 -37
  272. package/lib/module/ui/screens/trust/TrustRulesScreen.js.map +1 -1
  273. package/lib/module/ui/stores/resetSessionScopedStores.js +8 -3
  274. package/lib/module/ui/stores/resetSessionScopedStores.js.map +1 -1
  275. package/lib/module/ui/utils/avatarUtils.js +11 -2
  276. package/lib/module/ui/utils/avatarUtils.js.map +1 -1
  277. package/lib/module/ui/utils/fileManagement.js +0 -78
  278. package/lib/module/ui/utils/fileManagement.js.map +1 -1
  279. package/lib/typescript/commonjs/index.d.ts +2 -0
  280. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  281. package/lib/typescript/commonjs/ui/components/AvatarCameraBadge.d.ts +4 -0
  282. package/lib/typescript/commonjs/ui/components/AvatarCameraBadge.d.ts.map +1 -0
  283. package/lib/typescript/{module/ui/components/OxyAccountDialog.d.ts → commonjs/ui/components/OxyAccountDialogScreen.d.ts} +5 -4
  284. package/lib/typescript/commonjs/ui/components/OxyAccountDialogScreen.d.ts.map +1 -0
  285. package/lib/typescript/commonjs/ui/components/OxyAuthChooser.d.ts +3 -3
  286. package/lib/typescript/commonjs/ui/components/OxyAuthChooser.d.ts.map +1 -1
  287. package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts +2 -2
  288. package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts.map +1 -1
  289. package/lib/typescript/commonjs/ui/components/ProfileSummaryCard.d.ts.map +1 -1
  290. package/lib/typescript/commonjs/ui/components/RequireOxyAuth.d.ts +1 -1
  291. package/lib/typescript/commonjs/ui/components/SurfaceHeaderAction.d.ts +16 -0
  292. package/lib/typescript/commonjs/ui/components/SurfaceHeaderAction.d.ts.map +1 -0
  293. package/lib/typescript/commonjs/ui/components/SurfaceScreen.d.ts +3 -4
  294. package/lib/typescript/commonjs/ui/components/SurfaceScreen.d.ts.map +1 -1
  295. package/lib/typescript/commonjs/ui/components/fileManagement/FileDetailsModal.d.ts +14 -4
  296. package/lib/typescript/commonjs/ui/components/fileManagement/FileDetailsModal.d.ts.map +1 -1
  297. package/lib/typescript/commonjs/ui/components/modals/DeleteAccountModal.d.ts +17 -2
  298. package/lib/typescript/commonjs/ui/components/modals/DeleteAccountModal.d.ts.map +1 -1
  299. package/lib/typescript/commonjs/ui/components/oxyAuthChooserStyles.d.ts +75 -13
  300. package/lib/typescript/commonjs/ui/components/oxyAuthChooserStyles.d.ts.map +1 -1
  301. package/lib/typescript/commonjs/ui/components/photogrid/JustifiedPhotoGrid.d.ts +10 -8
  302. package/lib/typescript/commonjs/ui/components/photogrid/JustifiedPhotoGrid.d.ts.map +1 -1
  303. package/lib/typescript/commonjs/ui/components/surfaces/ActionSheetSurface.d.ts +38 -0
  304. package/lib/typescript/commonjs/ui/components/surfaces/ActionSheetSurface.d.ts.map +1 -0
  305. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
  306. package/lib/typescript/commonjs/ui/hooks/queries/queryKeys.d.ts +9 -0
  307. package/lib/typescript/commonjs/ui/hooks/queries/queryKeys.d.ts.map +1 -1
  308. package/lib/typescript/commonjs/ui/hooks/queries/useFileQueries.d.ts +50 -0
  309. package/lib/typescript/commonjs/ui/hooks/queries/useFileQueries.d.ts.map +1 -0
  310. package/lib/typescript/commonjs/ui/hooks/useAvatarPicker.d.ts +17 -16
  311. package/lib/typescript/commonjs/ui/hooks/useAvatarPicker.d.ts.map +1 -1
  312. package/lib/typescript/commonjs/ui/hooks/useReduceMotion.d.ts +14 -0
  313. package/lib/typescript/commonjs/ui/hooks/useReduceMotion.d.ts.map +1 -0
  314. package/lib/typescript/commonjs/ui/hooks/useSurfaceHeader.d.ts +31 -0
  315. package/lib/typescript/commonjs/ui/hooks/useSurfaceHeader.d.ts.map +1 -0
  316. package/lib/typescript/commonjs/ui/hooks/useSwitchableAccounts.d.ts +1 -1
  317. package/lib/typescript/commonjs/ui/navigation/accountDialogManager.d.ts +27 -2
  318. package/lib/typescript/commonjs/ui/navigation/accountDialogManager.d.ts.map +1 -1
  319. package/lib/typescript/commonjs/ui/navigation/bottomSheetManager.d.ts +4 -5
  320. package/lib/typescript/commonjs/ui/navigation/bottomSheetManager.d.ts.map +1 -1
  321. package/lib/typescript/commonjs/ui/navigation/routes.d.ts +1 -1
  322. package/lib/typescript/commonjs/ui/navigation/routes.d.ts.map +1 -1
  323. package/lib/typescript/commonjs/ui/navigation/surfaceBackBridge.d.ts +16 -0
  324. package/lib/typescript/commonjs/ui/navigation/surfaceBackBridge.d.ts.map +1 -0
  325. package/lib/typescript/commonjs/ui/navigation/surfaceNavStack.d.ts +21 -0
  326. package/lib/typescript/commonjs/ui/navigation/surfaceNavStack.d.ts.map +1 -1
  327. package/lib/typescript/commonjs/ui/navigation/surfaceRegistry.d.ts +101 -23
  328. package/lib/typescript/commonjs/ui/navigation/surfaceRegistry.d.ts.map +1 -1
  329. package/lib/typescript/commonjs/ui/navigation/surfaces.d.ts +42 -11
  330. package/lib/typescript/commonjs/ui/navigation/surfaces.d.ts.map +1 -1
  331. package/lib/typescript/commonjs/ui/screens/AccountMembersScreen.d.ts.map +1 -1
  332. package/lib/typescript/commonjs/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  333. package/lib/typescript/commonjs/ui/screens/AccountVerificationScreen.d.ts.map +1 -1
  334. package/lib/typescript/commonjs/ui/screens/AppInfoScreen.d.ts.map +1 -1
  335. package/lib/typescript/commonjs/ui/screens/AvatarCropScreen.d.ts +18 -9
  336. package/lib/typescript/commonjs/ui/screens/AvatarCropScreen.d.ts.map +1 -1
  337. package/lib/typescript/commonjs/ui/screens/ChangeAvatarScreen.d.ts +34 -0
  338. package/lib/typescript/commonjs/ui/screens/ChangeAvatarScreen.d.ts.map +1 -0
  339. package/lib/typescript/commonjs/ui/screens/ConnectedAppsScreen.d.ts.map +1 -1
  340. package/lib/typescript/commonjs/ui/screens/CreateAccountScreen.d.ts.map +1 -1
  341. package/lib/typescript/commonjs/ui/screens/EditProfileFieldScreen.d.ts.map +1 -1
  342. package/lib/typescript/commonjs/ui/screens/EditProfileScreen.d.ts.map +1 -1
  343. package/lib/typescript/commonjs/ui/screens/FAQScreen.d.ts.map +1 -1
  344. package/lib/typescript/commonjs/ui/screens/FeedbackScreen.d.ts.map +1 -1
  345. package/lib/typescript/commonjs/ui/screens/FileManagementScreen.d.ts.map +1 -1
  346. package/lib/typescript/commonjs/ui/screens/HelpSupportScreen.d.ts.map +1 -1
  347. package/lib/typescript/commonjs/ui/screens/HistoryViewScreen.d.ts.map +1 -1
  348. package/lib/typescript/commonjs/ui/screens/LanguageSelectorScreen.d.ts.map +1 -1
  349. package/lib/typescript/commonjs/ui/screens/LearnMoreUsernamesScreen.d.ts.map +1 -1
  350. package/lib/typescript/commonjs/ui/screens/LegalDocumentsScreen.d.ts.map +1 -1
  351. package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts +1 -1
  352. package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts.map +1 -1
  353. package/lib/typescript/commonjs/ui/screens/NotificationsScreen.d.ts.map +1 -1
  354. package/lib/typescript/commonjs/ui/screens/PaymentGatewayScreen.d.ts.map +1 -1
  355. package/lib/typescript/commonjs/ui/screens/PreferencesScreen.d.ts.map +1 -1
  356. package/lib/typescript/commonjs/ui/screens/PremiumSubscriptionScreen.d.ts.map +1 -1
  357. package/lib/typescript/commonjs/ui/screens/PrivacySettingsScreen.d.ts.map +1 -1
  358. package/lib/typescript/commonjs/ui/screens/ProfileScreen.d.ts.map +1 -1
  359. package/lib/typescript/commonjs/ui/screens/SavesCollectionsScreen.d.ts.map +1 -1
  360. package/lib/typescript/commonjs/ui/screens/SearchSettingsScreen.d.ts.map +1 -1
  361. package/lib/typescript/commonjs/ui/screens/UserLinksScreen.d.ts.map +1 -1
  362. package/lib/typescript/commonjs/ui/screens/UserListScreen.d.ts.map +1 -1
  363. package/lib/typescript/commonjs/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
  364. package/lib/typescript/commonjs/ui/screens/fileManagement/FileLibraryError.d.ts +23 -0
  365. package/lib/typescript/commonjs/ui/screens/fileManagement/FileLibraryError.d.ts.map +1 -0
  366. package/lib/typescript/commonjs/ui/screens/fileManagement/PhotoPickerSection.d.ts +4 -0
  367. package/lib/typescript/commonjs/ui/screens/fileManagement/PhotoPickerSection.d.ts.map +1 -1
  368. package/lib/typescript/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.d.ts +10 -2
  369. package/lib/typescript/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.d.ts.map +1 -1
  370. package/lib/typescript/commonjs/ui/screens/trust/TrustAboutScreen.d.ts.map +1 -1
  371. package/lib/typescript/commonjs/ui/screens/trust/TrustCenterScreen.d.ts.map +1 -1
  372. package/lib/typescript/commonjs/ui/screens/trust/TrustFAQScreen.d.ts.map +1 -1
  373. package/lib/typescript/commonjs/ui/screens/trust/TrustLeaderboardScreen.d.ts.map +1 -1
  374. package/lib/typescript/commonjs/ui/screens/trust/TrustRewardsScreen.d.ts.map +1 -1
  375. package/lib/typescript/commonjs/ui/screens/trust/TrustRulesScreen.d.ts.map +1 -1
  376. package/lib/typescript/commonjs/ui/stores/resetSessionScopedStores.d.ts +8 -1
  377. package/lib/typescript/commonjs/ui/stores/resetSessionScopedStores.d.ts.map +1 -1
  378. package/lib/typescript/commonjs/ui/types/navigation.d.ts +10 -0
  379. package/lib/typescript/commonjs/ui/types/navigation.d.ts.map +1 -1
  380. package/lib/typescript/commonjs/ui/utils/avatarUtils.d.ts.map +1 -1
  381. package/lib/typescript/commonjs/ui/utils/fileManagement.d.ts +0 -48
  382. package/lib/typescript/commonjs/ui/utils/fileManagement.d.ts.map +1 -1
  383. package/lib/typescript/module/index.d.ts +2 -0
  384. package/lib/typescript/module/index.d.ts.map +1 -1
  385. package/lib/typescript/module/ui/components/AvatarCameraBadge.d.ts +4 -0
  386. package/lib/typescript/module/ui/components/AvatarCameraBadge.d.ts.map +1 -0
  387. package/lib/typescript/{commonjs/ui/components/OxyAccountDialog.d.ts → module/ui/components/OxyAccountDialogScreen.d.ts} +5 -4
  388. package/lib/typescript/module/ui/components/OxyAccountDialogScreen.d.ts.map +1 -0
  389. package/lib/typescript/module/ui/components/OxyAuthChooser.d.ts +3 -3
  390. package/lib/typescript/module/ui/components/OxyAuthChooser.d.ts.map +1 -1
  391. package/lib/typescript/module/ui/components/ProfileButton.d.ts +2 -2
  392. package/lib/typescript/module/ui/components/ProfileButton.d.ts.map +1 -1
  393. package/lib/typescript/module/ui/components/ProfileSummaryCard.d.ts.map +1 -1
  394. package/lib/typescript/module/ui/components/RequireOxyAuth.d.ts +1 -1
  395. package/lib/typescript/module/ui/components/SurfaceHeaderAction.d.ts +16 -0
  396. package/lib/typescript/module/ui/components/SurfaceHeaderAction.d.ts.map +1 -0
  397. package/lib/typescript/module/ui/components/SurfaceScreen.d.ts +3 -4
  398. package/lib/typescript/module/ui/components/SurfaceScreen.d.ts.map +1 -1
  399. package/lib/typescript/module/ui/components/fileManagement/FileDetailsModal.d.ts +14 -4
  400. package/lib/typescript/module/ui/components/fileManagement/FileDetailsModal.d.ts.map +1 -1
  401. package/lib/typescript/module/ui/components/modals/DeleteAccountModal.d.ts +17 -2
  402. package/lib/typescript/module/ui/components/modals/DeleteAccountModal.d.ts.map +1 -1
  403. package/lib/typescript/module/ui/components/oxyAuthChooserStyles.d.ts +75 -13
  404. package/lib/typescript/module/ui/components/oxyAuthChooserStyles.d.ts.map +1 -1
  405. package/lib/typescript/module/ui/components/photogrid/JustifiedPhotoGrid.d.ts +10 -8
  406. package/lib/typescript/module/ui/components/photogrid/JustifiedPhotoGrid.d.ts.map +1 -1
  407. package/lib/typescript/module/ui/components/surfaces/ActionSheetSurface.d.ts +38 -0
  408. package/lib/typescript/module/ui/components/surfaces/ActionSheetSurface.d.ts.map +1 -0
  409. package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
  410. package/lib/typescript/module/ui/hooks/queries/queryKeys.d.ts +9 -0
  411. package/lib/typescript/module/ui/hooks/queries/queryKeys.d.ts.map +1 -1
  412. package/lib/typescript/module/ui/hooks/queries/useFileQueries.d.ts +50 -0
  413. package/lib/typescript/module/ui/hooks/queries/useFileQueries.d.ts.map +1 -0
  414. package/lib/typescript/module/ui/hooks/useAvatarPicker.d.ts +17 -16
  415. package/lib/typescript/module/ui/hooks/useAvatarPicker.d.ts.map +1 -1
  416. package/lib/typescript/module/ui/hooks/useReduceMotion.d.ts +14 -0
  417. package/lib/typescript/module/ui/hooks/useReduceMotion.d.ts.map +1 -0
  418. package/lib/typescript/module/ui/hooks/useSurfaceHeader.d.ts +31 -0
  419. package/lib/typescript/module/ui/hooks/useSurfaceHeader.d.ts.map +1 -0
  420. package/lib/typescript/module/ui/hooks/useSwitchableAccounts.d.ts +1 -1
  421. package/lib/typescript/module/ui/navigation/accountDialogManager.d.ts +27 -2
  422. package/lib/typescript/module/ui/navigation/accountDialogManager.d.ts.map +1 -1
  423. package/lib/typescript/module/ui/navigation/bottomSheetManager.d.ts +4 -5
  424. package/lib/typescript/module/ui/navigation/bottomSheetManager.d.ts.map +1 -1
  425. package/lib/typescript/module/ui/navigation/routes.d.ts +1 -1
  426. package/lib/typescript/module/ui/navigation/routes.d.ts.map +1 -1
  427. package/lib/typescript/module/ui/navigation/surfaceBackBridge.d.ts +16 -0
  428. package/lib/typescript/module/ui/navigation/surfaceBackBridge.d.ts.map +1 -0
  429. package/lib/typescript/module/ui/navigation/surfaceNavStack.d.ts +21 -0
  430. package/lib/typescript/module/ui/navigation/surfaceNavStack.d.ts.map +1 -1
  431. package/lib/typescript/module/ui/navigation/surfaceRegistry.d.ts +101 -23
  432. package/lib/typescript/module/ui/navigation/surfaceRegistry.d.ts.map +1 -1
  433. package/lib/typescript/module/ui/navigation/surfaces.d.ts +42 -11
  434. package/lib/typescript/module/ui/navigation/surfaces.d.ts.map +1 -1
  435. package/lib/typescript/module/ui/screens/AccountMembersScreen.d.ts.map +1 -1
  436. package/lib/typescript/module/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  437. package/lib/typescript/module/ui/screens/AccountVerificationScreen.d.ts.map +1 -1
  438. package/lib/typescript/module/ui/screens/AppInfoScreen.d.ts.map +1 -1
  439. package/lib/typescript/module/ui/screens/AvatarCropScreen.d.ts +18 -9
  440. package/lib/typescript/module/ui/screens/AvatarCropScreen.d.ts.map +1 -1
  441. package/lib/typescript/module/ui/screens/ChangeAvatarScreen.d.ts +34 -0
  442. package/lib/typescript/module/ui/screens/ChangeAvatarScreen.d.ts.map +1 -0
  443. package/lib/typescript/module/ui/screens/ConnectedAppsScreen.d.ts.map +1 -1
  444. package/lib/typescript/module/ui/screens/CreateAccountScreen.d.ts.map +1 -1
  445. package/lib/typescript/module/ui/screens/EditProfileFieldScreen.d.ts.map +1 -1
  446. package/lib/typescript/module/ui/screens/EditProfileScreen.d.ts.map +1 -1
  447. package/lib/typescript/module/ui/screens/FAQScreen.d.ts.map +1 -1
  448. package/lib/typescript/module/ui/screens/FeedbackScreen.d.ts.map +1 -1
  449. package/lib/typescript/module/ui/screens/FileManagementScreen.d.ts.map +1 -1
  450. package/lib/typescript/module/ui/screens/HelpSupportScreen.d.ts.map +1 -1
  451. package/lib/typescript/module/ui/screens/HistoryViewScreen.d.ts.map +1 -1
  452. package/lib/typescript/module/ui/screens/LanguageSelectorScreen.d.ts.map +1 -1
  453. package/lib/typescript/module/ui/screens/LearnMoreUsernamesScreen.d.ts.map +1 -1
  454. package/lib/typescript/module/ui/screens/LegalDocumentsScreen.d.ts.map +1 -1
  455. package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts +1 -1
  456. package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts.map +1 -1
  457. package/lib/typescript/module/ui/screens/NotificationsScreen.d.ts.map +1 -1
  458. package/lib/typescript/module/ui/screens/PaymentGatewayScreen.d.ts.map +1 -1
  459. package/lib/typescript/module/ui/screens/PreferencesScreen.d.ts.map +1 -1
  460. package/lib/typescript/module/ui/screens/PremiumSubscriptionScreen.d.ts.map +1 -1
  461. package/lib/typescript/module/ui/screens/PrivacySettingsScreen.d.ts.map +1 -1
  462. package/lib/typescript/module/ui/screens/ProfileScreen.d.ts.map +1 -1
  463. package/lib/typescript/module/ui/screens/SavesCollectionsScreen.d.ts.map +1 -1
  464. package/lib/typescript/module/ui/screens/SearchSettingsScreen.d.ts.map +1 -1
  465. package/lib/typescript/module/ui/screens/UserLinksScreen.d.ts.map +1 -1
  466. package/lib/typescript/module/ui/screens/UserListScreen.d.ts.map +1 -1
  467. package/lib/typescript/module/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
  468. package/lib/typescript/module/ui/screens/fileManagement/FileLibraryError.d.ts +23 -0
  469. package/lib/typescript/module/ui/screens/fileManagement/FileLibraryError.d.ts.map +1 -0
  470. package/lib/typescript/module/ui/screens/fileManagement/PhotoPickerSection.d.ts +4 -0
  471. package/lib/typescript/module/ui/screens/fileManagement/PhotoPickerSection.d.ts.map +1 -1
  472. package/lib/typescript/module/ui/screens/fileManagement/hooks/useFileUploadState.d.ts +10 -2
  473. package/lib/typescript/module/ui/screens/fileManagement/hooks/useFileUploadState.d.ts.map +1 -1
  474. package/lib/typescript/module/ui/screens/trust/TrustAboutScreen.d.ts.map +1 -1
  475. package/lib/typescript/module/ui/screens/trust/TrustCenterScreen.d.ts.map +1 -1
  476. package/lib/typescript/module/ui/screens/trust/TrustFAQScreen.d.ts.map +1 -1
  477. package/lib/typescript/module/ui/screens/trust/TrustLeaderboardScreen.d.ts.map +1 -1
  478. package/lib/typescript/module/ui/screens/trust/TrustRewardsScreen.d.ts.map +1 -1
  479. package/lib/typescript/module/ui/screens/trust/TrustRulesScreen.d.ts.map +1 -1
  480. package/lib/typescript/module/ui/stores/resetSessionScopedStores.d.ts +8 -1
  481. package/lib/typescript/module/ui/stores/resetSessionScopedStores.d.ts.map +1 -1
  482. package/lib/typescript/module/ui/types/navigation.d.ts +10 -0
  483. package/lib/typescript/module/ui/types/navigation.d.ts.map +1 -1
  484. package/lib/typescript/module/ui/utils/avatarUtils.d.ts.map +1 -1
  485. package/lib/typescript/module/ui/utils/fileManagement.d.ts +0 -48
  486. package/lib/typescript/module/ui/utils/fileManagement.d.ts.map +1 -1
  487. package/package.json +9 -5
  488. package/src/index.ts +12 -5
  489. package/src/ui/components/AvatarCameraBadge.tsx +35 -0
  490. package/src/ui/components/{OxyAccountDialog.tsx → OxyAccountDialogScreen.tsx} +50 -116
  491. package/src/ui/components/OxyAuthChooser.tsx +743 -86
  492. package/src/ui/components/OxyConsentScreen.tsx +1 -1
  493. package/src/ui/components/ProfileButton.tsx +18 -3
  494. package/src/ui/components/ProfileSummaryCard.tsx +2 -25
  495. package/src/ui/components/RequireOxyAuth.tsx +1 -1
  496. package/src/ui/components/SurfaceHeaderAction.tsx +60 -0
  497. package/src/ui/components/SurfaceScreen.tsx +108 -14
  498. package/src/ui/components/fileManagement/FileDetailsModal.tsx +50 -36
  499. package/src/ui/components/modals/DeleteAccountModal.tsx +47 -26
  500. package/src/ui/components/oxyAuthChooserStyles.ts +78 -16
  501. package/src/ui/components/photogrid/JustifiedPhotoGrid.tsx +158 -84
  502. package/src/ui/components/photogrid/__tests__/chunkPhotos.test.ts +51 -0
  503. package/src/ui/components/surfaces/ActionSheetSurface.tsx +98 -0
  504. package/src/ui/context/OxyContext.tsx +79 -25
  505. package/src/ui/hooks/queries/queryKeys.ts +15 -0
  506. package/src/ui/hooks/queries/useFileQueries.ts +162 -0
  507. package/src/ui/hooks/useAvatarPicker.ts +46 -74
  508. package/src/ui/hooks/useReduceMotion.ts +58 -0
  509. package/src/ui/hooks/useSurfaceHeader.ts +57 -0
  510. package/src/ui/hooks/useSwitchableAccounts.ts +1 -1
  511. package/src/ui/navigation/__tests__/getSurfaceConfig.test.ts +55 -7
  512. package/src/ui/navigation/__tests__/surfaceNavStack.test.ts +149 -0
  513. package/src/ui/navigation/accountDialogManager.ts +42 -2
  514. package/src/ui/navigation/bottomSheetManager.ts +6 -7
  515. package/src/ui/navigation/routes.ts +6 -4
  516. package/src/ui/navigation/surfaceBackBridge.ts +69 -0
  517. package/src/ui/navigation/surfaceNavStack.ts +72 -9
  518. package/src/ui/navigation/surfaceRegistry.ts +164 -24
  519. package/src/ui/navigation/surfaces.ts +137 -30
  520. package/src/ui/screens/AccountMembersScreen.tsx +39 -100
  521. package/src/ui/screens/AccountSettingsScreen.tsx +32 -54
  522. package/src/ui/screens/AccountVerificationScreen.tsx +23 -51
  523. package/src/ui/screens/AppInfoScreen.tsx +6 -13
  524. package/src/ui/screens/AvatarCropScreen.tsx +340 -311
  525. package/src/ui/screens/ChangeAvatarScreen.tsx +359 -0
  526. package/src/ui/screens/ConnectedAppsScreen.tsx +39 -60
  527. package/src/ui/screens/CreateAccountScreen.tsx +13 -39
  528. package/src/ui/screens/EditProfileFieldScreen.tsx +30 -48
  529. package/src/ui/screens/EditProfileScreen.tsx +7 -16
  530. package/src/ui/screens/FAQScreen.tsx +9 -13
  531. package/src/ui/screens/FeedbackScreen.tsx +8 -22
  532. package/src/ui/screens/FileManagementScreen.tsx +370 -610
  533. package/src/ui/screens/HelpSupportScreen.tsx +7 -13
  534. package/src/ui/screens/HistoryViewScreen.tsx +26 -31
  535. package/src/ui/screens/LanguageSelectorScreen.tsx +12 -46
  536. package/src/ui/screens/LearnMoreUsernamesScreen.tsx +8 -16
  537. package/src/ui/screens/LegalDocumentsScreen.tsx +7 -22
  538. package/src/ui/screens/ManageAccountScreen.tsx +96 -165
  539. package/src/ui/screens/NotificationsScreen.tsx +7 -13
  540. package/src/ui/screens/PaymentGatewayScreen.tsx +3 -10
  541. package/src/ui/screens/PreferencesScreen.tsx +7 -13
  542. package/src/ui/screens/PremiumSubscriptionScreen.tsx +52 -90
  543. package/src/ui/screens/PrivacySettingsScreen.tsx +9 -21
  544. package/src/ui/screens/ProfileScreen.tsx +9 -11
  545. package/src/ui/screens/SavesCollectionsScreen.tsx +7 -13
  546. package/src/ui/screens/SearchSettingsScreen.tsx +9 -21
  547. package/src/ui/screens/UserLinksScreen.tsx +7 -14
  548. package/src/ui/screens/UserListScreen.tsx +2 -5
  549. package/src/ui/screens/WelcomeNewUserScreen.tsx +18 -48
  550. package/src/ui/screens/fileManagement/FileLibraryError.tsx +56 -0
  551. package/src/ui/screens/fileManagement/PhotoPickerSection.tsx +56 -46
  552. package/src/ui/screens/fileManagement/hooks/useFileUploadState.ts +55 -71
  553. package/src/ui/screens/trust/TrustAboutScreen.tsx +10 -17
  554. package/src/ui/screens/trust/TrustCenterScreen.tsx +9 -28
  555. package/src/ui/screens/trust/TrustFAQScreen.tsx +15 -18
  556. package/src/ui/screens/trust/TrustLeaderboardScreen.tsx +3 -5
  557. package/src/ui/screens/trust/TrustRewardsScreen.tsx +11 -26
  558. package/src/ui/screens/trust/TrustRulesScreen.tsx +10 -13
  559. package/src/ui/stores/resetSessionScopedStores.ts +8 -3
  560. package/src/ui/types/navigation.ts +10 -0
  561. package/src/ui/utils/avatarUtils.ts +11 -2
  562. package/src/ui/utils/fileManagement.ts +1 -101
  563. package/lib/commonjs/ui/components/Header.js +0 -305
  564. package/lib/commonjs/ui/components/Header.js.map +0 -1
  565. package/lib/commonjs/ui/components/OxyAccountDialog.js.map +0 -1
  566. package/lib/commonjs/ui/stores/fileStore.js +0 -153
  567. package/lib/commonjs/ui/stores/fileStore.js.map +0 -1
  568. package/lib/module/ui/components/Header.js +0 -299
  569. package/lib/module/ui/components/Header.js.map +0 -1
  570. package/lib/module/ui/components/OxyAccountDialog.js.map +0 -1
  571. package/lib/module/ui/stores/fileStore.js +0 -145
  572. package/lib/module/ui/stores/fileStore.js.map +0 -1
  573. package/lib/typescript/commonjs/ui/components/Header.d.ts +0 -33
  574. package/lib/typescript/commonjs/ui/components/Header.d.ts.map +0 -1
  575. package/lib/typescript/commonjs/ui/components/OxyAccountDialog.d.ts.map +0 -1
  576. package/lib/typescript/commonjs/ui/stores/fileStore.d.ts +0 -31
  577. package/lib/typescript/commonjs/ui/stores/fileStore.d.ts.map +0 -1
  578. package/lib/typescript/module/ui/components/Header.d.ts +0 -33
  579. package/lib/typescript/module/ui/components/Header.d.ts.map +0 -1
  580. package/lib/typescript/module/ui/components/OxyAccountDialog.d.ts.map +0 -1
  581. package/lib/typescript/module/ui/stores/fileStore.d.ts +0 -31
  582. package/lib/typescript/module/ui/stores/fileStore.d.ts.map +0 -1
  583. package/src/ui/components/Header.tsx +0 -224
  584. package/src/ui/stores/fileStore.ts +0 -118
@@ -4,8 +4,8 @@
4
4
  *
5
5
  * A thin React Native binding over the headless `AccountDialogController` in
6
6
  * `@oxyhq/core` (bound via `useSyncExternalStore`) — the same data/state
7
- * machine {@link OxyAccountDialog} renders, extracted so it can be mounted in
8
- * TWO places: wrapped in Bloom's `<Dialog>` by `OxyAccountDialog` (the normal
7
+ * machine {@link OxyAccountDialogScreen} renders, extracted so it can be mounted in
8
+ * TWO places: wrapped in Bloom's `<Dialog>` by `OxyAccountDialogScreen` (the normal
9
9
  * in-app surface), and mounted bare by a future auth.oxy.so hub page for the
10
10
  * cross-origin passkey popup (b2) — same chooser, two hosts, two completion
11
11
  * strategies via the `onComplete` prop. Neither host duplicates view logic.
@@ -47,7 +47,14 @@
47
47
  */
48
48
 
49
49
  import type React from 'react';
50
- import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react';
50
+ import {
51
+ Fragment,
52
+ useCallback,
53
+ useMemo,
54
+ useRef,
55
+ useState,
56
+ useSyncExternalStore,
57
+ } from 'react';
51
58
  import {
52
59
  Linking,
53
60
  Platform,
@@ -57,10 +64,21 @@ import {
57
64
  type StyleProp,
58
65
  type ViewStyle,
59
66
  } from 'react-native';
67
+ import Animated, {
68
+ Extrapolation,
69
+ interpolate,
70
+ useAnimatedStyle,
71
+ useSharedValue,
72
+ withTiming,
73
+ } from 'react-native-reanimated';
60
74
  import { MaterialCommunityIcons } from '@expo/vector-icons';
61
75
  import QRCode from 'react-native-qrcode-svg';
62
76
  import { Avatar } from '@oxyhq/bloom/avatar';
77
+ import { AvatarGroup, type AvatarGroupItem } from '@oxyhq/bloom/avatar-group';
63
78
  import { Button } from '@oxyhq/bloom/button';
79
+ import { PressableScale } from '@oxyhq/bloom/pressable-scale';
80
+ import { CompositionBar, type CompositionCategory } from '@oxyhq/bloom/composition-bar';
81
+ import { SettingsListGroup, SettingsListItem } from '@oxyhq/bloom/settings-list';
64
82
  import { toast } from '@oxyhq/bloom';
65
83
  import { Text } from '@oxyhq/bloom/typography';
66
84
  import {
@@ -71,15 +89,18 @@ import {
71
89
  type AppColorName,
72
90
  } from '@oxyhq/bloom/theme';
73
91
  import type { AccountDialogSnapshot, OxyServices, SwitchableAccount } from '@oxyhq/core';
74
- import { isOxyRpOrigin } from '@oxyhq/core';
92
+ import { getNormalizedUserHandle, isOxyRpOrigin } from '@oxyhq/core';
75
93
  import { useQueryClient } from '@tanstack/react-query';
76
94
  import { useOxy } from '../context/OxyContext';
77
95
  import { useI18n } from '../hooks/useI18n';
96
+ import { getAccountDialogConsumerHooks } from '../navigation/accountDialogManager';
78
97
  import { isWebBrowser } from '../utils/isWebBrowser';
79
98
  import { getCommonsAcquisitionUrl } from '../utils/commonsStoreLinks';
99
+ import { useAccountStorageUsage } from '../hooks/queries/useServicesQueries';
80
100
  import { authChooserStyles as styles } from './oxyAuthChooserStyles';
101
+ import AvatarCameraBadge from './AvatarCameraBadge';
81
102
 
82
- /** Diameter of a row avatar. */
103
+ /** Diameter of a row avatar (the sign-in view's account rows). */
83
104
  const ROW_AVATAR_SIZE = 40;
84
105
  /** High-contrast QR colors — intentionally fixed (NOT themed) for scan reliability. */
85
106
  const QR_PLATE_BG = '#FFFFFF';
@@ -87,6 +108,13 @@ const QR_FOREGROUND = '#000000';
87
108
  const QR_SIZE = 196;
88
109
  /** Commons' own identity-creation deep link (mirrors the `approve`/`attest`/`card` intents). */
89
110
  const COMMONS_CREATE_IDENTITY_URL = 'oxycommons://create-identity';
111
+ /**
112
+ * "Accounts by Oxy" management app — the canonical home for account settings,
113
+ * data export, and storage management. The account-menu rows deep-link into it
114
+ * (`/data`, `/storage`, or its root) the same way `getCommonsAcquisitionUrl`
115
+ * hands off to Commons; nothing here invents new API endpoints.
116
+ */
117
+ const ACCOUNTS_APP_URL = 'https://accounts.oxy.so';
90
118
 
91
119
  export interface OxyAuthChooserProps {
92
120
  /** Called after a completed switch, sign-in, or sign-up. */
@@ -116,13 +144,20 @@ interface OxyAuthChooserHandlers {
116
144
  onSwitch: (accountId: string) => void;
117
145
  onAdd: () => void;
118
146
  onManage: () => void;
147
+ /**
148
+ * Change the current account's photo — opens the avatar-change flow. Because
149
+ * the account menu lives in the AccountDialog surface, this MORPHS that surface
150
+ * into `ChangeAvatar` (via `openAvatarPicker` → `openWithinOrPresent`), the same
151
+ * flow ManageAccount's avatar uses; it never stacks a new dialog.
152
+ */
153
+ onEditAvatar: () => void;
119
154
  }
120
155
 
121
156
  type Theme = ReturnType<typeof useTheme>;
122
157
  type Translate = ReturnType<typeof useI18n>['t'];
123
158
 
124
159
  /**
125
- * The account switcher + sign-in/sign-up chooser. Mounted by `OxyAccountDialog`
160
+ * The account switcher + sign-in/sign-up chooser. Mounted by `OxyAccountDialogScreen`
126
161
  * (wrapped in Bloom's `<Dialog>`) today; mountable bare by any future host that
127
162
  * supplies its own `onComplete`.
128
163
  */
@@ -134,6 +169,8 @@ const OxyAuthChooser: React.FC<OxyAuthChooserProps> = ({ onComplete }) => {
134
169
  signInWithPasskey,
135
170
  registerWithPasskey,
136
171
  oxyServices,
172
+ logout,
173
+ openAvatarPicker,
137
174
  } = useOxy();
138
175
  const theme = useTheme();
139
176
  const { t } = useI18n();
@@ -196,12 +233,57 @@ const OxyAuthChooser: React.FC<OxyAuthChooserProps> = ({ onComplete }) => {
196
233
  [createPasskeyPending, registerWithPasskey, onComplete, t],
197
234
  );
198
235
 
236
+ // Web: auto-start "Sign in with Oxy" when the sign-in entry becomes the shown
237
+ // view — the QR handoff is the PRIMARY web surface, not a button behind a tap.
238
+ // `signInWithOxy()` tries the shared keychain first (silently, native-only)
239
+ // then falls to the QR handoff, which is what actually renders. Driven from the
240
+ // EVENTS that reach that view — the initial `subscribe` pass below (an
241
+ // open-to-sign-in) and the add / back-to-sign-in handlers — never a watcher
242
+ // effect. Guarded so it never restarts a live flow (phase must be idle) and is a
243
+ // no-op on native (button-driven). Reads the live snapshot at call time (an
244
+ // event callback, not render), so it is stable across renders.
245
+ const autoStartSignIn = useCallback(() => {
246
+ if (!controller || !isWebBrowser()) return;
247
+ const { view: currentView, signIn } = controller.getSnapshot();
248
+ if ((currentView !== 'signin' && currentView !== 'add') || signIn.phase !== 'idle') return;
249
+ void controller.signInWithOxy();
250
+ }, [controller]);
251
+
199
252
  // Bind the headless controller. `getSnapshot` returns a stable reference
200
253
  // between changes, so it is `useSyncExternalStore`-safe. Guard the no-provider
201
254
  // loading state (`controller` is `null`) with an inert store.
255
+ //
256
+ // The subscribe callback ALSO carries two owner-mandated reactions to the
257
+ // controller. These run in the subscribe / notification callbacks — EVENT
258
+ // callbacks, not render/effect — so neither is a React effect hook:
259
+ // 1. Sign-in device-flow failures (poll / socket / popup-cancel land on
260
+ // `signIn` asynchronously) are toasted at the notification site, deduped
261
+ // per subscription — NEVER an inline banner in the QR view (owner mandate,
262
+ // same contract as account-switch).
263
+ // 2. On subscribe (mount / re-subscribe — a passive effect, the SAME timing
264
+ // the removed effects had) the web sign-in flow auto-starts if the opening
265
+ // view is the sign-in entry.
202
266
  const subscribe = useCallback(
203
- (listener: () => void) => (controller ? controller.subscribe(listener) : () => undefined),
204
- [controller],
267
+ (listener: () => void) => {
268
+ if (!controller) return () => undefined;
269
+ let lastToastedSignInError: string | null = null;
270
+ const maybeToastSignInError = () => {
271
+ const { signIn } = controller.getSnapshot();
272
+ if (signIn.phase === 'error' && signIn.error && signIn.error !== lastToastedSignInError) {
273
+ lastToastedSignInError = signIn.error;
274
+ toast.error(signIn.error);
275
+ } else if (signIn.phase !== 'error') {
276
+ lastToastedSignInError = null;
277
+ }
278
+ };
279
+ maybeToastSignInError();
280
+ autoStartSignIn();
281
+ return controller.subscribe(() => {
282
+ maybeToastSignInError();
283
+ listener();
284
+ });
285
+ },
286
+ [controller, autoStartSignIn],
205
287
  );
206
288
  const getSnapshot = useCallback(
207
289
  () => (controller ? controller.getSnapshot() : EMPTY_SNAPSHOT),
@@ -210,44 +292,6 @@ const OxyAuthChooser: React.FC<OxyAuthChooserProps> = ({ onComplete }) => {
210
292
  const snapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
211
293
  const { view } = snapshot;
212
294
 
213
- // Sign-in device-flow failures land on `snapshot.signIn` asynchronously (poll /
214
- // socket / popup cancel). Toast at the controller notification site — never an
215
- // inline banner in the QR view (owner mandate, same contract as account-switch).
216
- useEffect(() => {
217
- if (!controller) return;
218
- let lastToastedSignInError: string | null = null;
219
- const maybeToastSignInError = () => {
220
- const { signIn } = controller.getSnapshot();
221
- if (signIn.phase === 'error' && signIn.error && signIn.error !== lastToastedSignInError) {
222
- lastToastedSignInError = signIn.error;
223
- toast.error(
224
- signIn.error ||
225
- t('accountSwitcher.toasts.signInFailed') ||
226
- 'Sign-in failed. Please try again.',
227
- );
228
- }
229
- if (signIn.phase !== 'error') {
230
- lastToastedSignInError = null;
231
- }
232
- };
233
- maybeToastSignInError();
234
- return controller.subscribe(maybeToastSignInError);
235
- }, [controller, t]);
236
-
237
- // Web: "Sign in with Oxy" auto-starts the instant the sign-in entry is
238
- // reached — no button tap needed. `signInWithOxy()` tries the shared
239
- // keychain first (silently, native-only) then falls to the QR handoff,
240
- // which is what actually renders: the QR is the primary web surface, not a
241
- // peer button among several. Gated on `phase === 'idle'` so navigating back
242
- // to this view while a flow is already active (or re-entering it) never
243
- // restarts/duplicates it. Native stays fully button-driven (unchanged) —
244
- // this effect is a no-op there.
245
- useEffect(() => {
246
- if (!controller || !isWebBrowser()) return;
247
- if ((view !== 'signin' && view !== 'add') || snapshot.signIn.phase !== 'idle') return;
248
- void controller.signInWithOxy();
249
- }, [controller, view, snapshot.signIn.phase]);
250
-
251
295
  const [switching, setSwitching] = useState(false);
252
296
 
253
297
  const handleSwitch = useCallback(
@@ -286,26 +330,98 @@ const OxyAuthChooser: React.FC<OxyAuthChooserProps> = ({ onComplete }) => {
286
330
 
287
331
  const handleManage = useCallback(() => {
288
332
  onComplete?.();
333
+ const hooks = getAccountDialogConsumerHooks();
334
+ if (hooks?.onNavigateManage) {
335
+ hooks.onNavigateManage();
336
+ return;
337
+ }
289
338
  showBottomSheet?.('ManageAccount');
290
339
  }, [onComplete, showBottomSheet]);
291
340
 
341
+ const handleAdd = useCallback(() => {
342
+ const hooks = getAccountDialogConsumerHooks();
343
+ if (hooks?.onAddAccount) {
344
+ hooks.onAddAccount();
345
+ return;
346
+ }
347
+ // No consumer override: enter the "add account" view and auto-start the web
348
+ // sign-in flow, from this handler (the event that reaches the view).
349
+ controller?.add();
350
+ autoStartSignIn();
351
+ }, [controller, autoStartSignIn]);
352
+
292
353
  const handlers = useMemo<OxyAuthChooserHandlers>(
293
354
  () => ({
294
355
  onSwitch: (accountId) => {
295
356
  void handleSwitch(accountId);
296
357
  },
297
- onAdd: () => controller?.add(),
358
+ onAdd: handleAdd,
298
359
  onManage: handleManage,
360
+ // Morphs the AccountDialog surface into `ChangeAvatar` (and back), then
361
+ // uploads / clears the picked photo — the single shared avatar write path.
362
+ onEditAvatar: () => openAvatarPicker(),
299
363
  }),
300
- [handleSwitch, controller, handleManage],
364
+ [handleSwitch, handleAdd, handleManage, openAvatarPicker],
365
+ );
366
+
367
+ // Real storage usage for the account menu's "Oxy storage" block. Disabled
368
+ // (no fetch) until a private-API session exists, so it is inert on the
369
+ // sign-in/QR/sign-up views; when present the block shows live used/total.
370
+ const storageQuery = useAccountStorageUsage();
371
+ const storage = useMemo<AccountStorageModel | null>(
372
+ () =>
373
+ storageQuery.data
374
+ ? {
375
+ usedBytes: storageQuery.data.totalUsedBytes,
376
+ limitBytes: storageQuery.data.totalLimitBytes,
377
+ }
378
+ : null,
379
+ [storageQuery.data],
301
380
  );
302
381
 
382
+ // The account-menu rows below the switcher: storage + data + settings + help
383
+ // deep-link into the "Accounts by Oxy" app or open the matching in-app sheet
384
+ // (Help, Legal); sign-out uses the SDK's own per-account sign-out. No new
385
+ // endpoints — the same handoff pattern `handleManage`/`getCommonsAcquisitionUrl`
386
+ // already use.
387
+ const accountMenu = useMemo<AccountsMenuActions>(() => {
388
+ const openUrl = (url: string) => {
389
+ void Linking.openURL(url);
390
+ };
391
+ const openSheet = (config: Parameters<NonNullable<typeof showBottomSheet>>[0]) => {
392
+ onComplete?.();
393
+ showBottomSheet?.(config);
394
+ };
395
+ return {
396
+ onOpenSettings: () => openUrl(ACCOUNTS_APP_URL),
397
+ onOpenData: () => openUrl(`${ACCOUNTS_APP_URL}/data`),
398
+ onManageStorage: () => openUrl(`${ACCOUNTS_APP_URL}/storage`),
399
+ onUpgradeStorage: () => openUrl(`${ACCOUNTS_APP_URL}/storage`),
400
+ onHelp: () => openSheet('HelpSupport'),
401
+ onPrivacy: () => openSheet({ screen: 'LegalDocuments', props: { initialStep: 1 } }),
402
+ onTerms: () => openSheet({ screen: 'LegalDocuments', props: { initialStep: 2 } }),
403
+ onSignOut: () => {
404
+ void logout();
405
+ onComplete?.();
406
+ },
407
+ };
408
+ }, [onComplete, showBottomSheet, logout]);
409
+
303
410
  if (!controller) {
304
411
  return null;
305
412
  }
306
413
 
307
414
  if (view === 'accounts') {
308
- return <AccountsView snapshot={snapshot} theme={theme} t={t} handlers={handlers} />;
415
+ return (
416
+ <AccountsView
417
+ snapshot={snapshot}
418
+ theme={theme}
419
+ t={t}
420
+ handlers={handlers}
421
+ storage={storage}
422
+ menu={accountMenu}
423
+ />
424
+ );
309
425
  }
310
426
 
311
427
  if (view === 'qr') {
@@ -342,7 +458,10 @@ const OxyAuthChooser: React.FC<OxyAuthChooserProps> = ({ onComplete }) => {
342
458
  onCreateWithPasskey={handleCreateWithPasskey}
343
459
  createPending={createPasskeyPending}
344
460
  onOpenHub={() => void controller.startPasskeyHubSignIn()}
345
- onBackToSignIn={() => controller.setView('signin')}
461
+ onBackToSignIn={() => {
462
+ controller.setView('signin');
463
+ autoStartSignIn();
464
+ }}
346
465
  />
347
466
  );
348
467
  }
@@ -361,66 +480,604 @@ const OxyAuthChooser: React.FC<OxyAuthChooserProps> = ({ onComplete }) => {
361
480
  };
362
481
 
363
482
  // ---------------------------------------------------------------------------
364
- // Accounts view
483
+ // Accounts view — the signed-in Oxy account MENU (NativeWind)
365
484
  // ---------------------------------------------------------------------------
366
485
 
486
+ /** Used/total storage bytes for the "Oxy storage" block, or `null` when unknown. */
487
+ interface AccountStorageModel {
488
+ usedBytes: number;
489
+ limitBytes: number;
490
+ }
491
+
492
+ /** The account-menu row actions the container wires (deep-links / sheets / sign-out). */
493
+ interface AccountsMenuActions {
494
+ onOpenSettings: () => void;
495
+ onOpenData: () => void;
496
+ onManageStorage: () => void;
497
+ onUpgradeStorage: () => void;
498
+ onHelp: () => void;
499
+ onPrivacy: () => void;
500
+ onTerms: () => void;
501
+ onSignOut: () => void;
502
+ }
503
+
367
504
  interface AccountsViewProps {
368
505
  snapshot: AccountDialogSnapshot;
369
506
  theme: Theme;
370
507
  t: Translate;
371
508
  handlers: OxyAuthChooserHandlers;
509
+ storage: AccountStorageModel | null;
510
+ menu: AccountsMenuActions;
511
+ }
512
+
513
+ /**
514
+ * Leading glyph for the rows that live in a Bloom grouped section (the MENU
515
+ * block) and for the storage card's cloud, which lines its title up with them.
516
+ * It is Bloom's OWN icon-slot size: `SettingsListItem` reserves a fixed 20px
517
+ * leading column and Bloom is consumed exactly as it ships, so a menu glyph
518
+ * larger than this would overhang into the row's title.
519
+ */
520
+ const ROW_ICON_SIZE = 20;
521
+ /**
522
+ * The switch card's two corner states. Collapsed it is one row and reads as a
523
+ * PILL; opened it is a card holding rows, on the same 16px corner the Bloom
524
+ * grouped section below it uses. Interpolated across the reveal, never snapped.
525
+ */
526
+ const SWITCH_CARD_PILL_RADIUS = 999;
527
+ const SWITCH_CARD_RADIUS = 16;
528
+ /**
529
+ * The fraction of the reveal over which the corner resolves. The corner is a
530
+ * FASTER gesture than the reveal — it has to be finished before the rows read as
531
+ * rows, or the card still looks like a pill while a list falls out of it — so it
532
+ * is clamped to the reveal's opening fraction instead of tracking it end to end.
533
+ * Measured in a browser against the 240ms reveal: the corner reaches its card
534
+ * value ~120ms in, with the list only ~20% revealed, and (mirrored) the pill is
535
+ * back ~250ms into the close, with the list already down to ~0.
536
+ */
537
+ const SWITCH_CARD_RADIUS_SETTLE = 0.2;
538
+ /** Diameter of an account row's avatar in the switch list (own markup). */
539
+ const SWITCH_AVATAR_SIZE = 36;
540
+ /** Glyph inside a bordered affordance badge, sized to the avatar it stands in for. */
541
+ const BADGE_GLYPH_SIZE = 19;
542
+ /** The hero block's large current-account avatar. */
543
+ const HERO_AVATAR_SIZE = 72;
544
+
545
+ /**
546
+ * The hero's address line, shown under the "Hi, <name>!" greeting: the account's
547
+ * canonical `@oxy.so` email when it has one, else its normalized `@handle`. Never
548
+ * synthesizes a `username@oxy.so` address (the identity contract forbids it) — a
549
+ * non-Oxy or missing email falls back to `getNormalizedUserHandle`.
550
+ */
551
+ function heroAddressLine(account: SwitchableAccount): string | null {
552
+ if (account.email?.toLowerCase().endsWith('@oxy.so')) {
553
+ return account.email;
554
+ }
555
+ const handle = getNormalizedUserHandle(account.user);
556
+ return handle ? `@${handle}` : null;
372
557
  }
558
+ /** Avatars shown in the switch row's facepile before it collapses into `+N`. */
559
+ const FACEPILE_MAX = 2;
560
+ /** Facepile avatar diameter — one clear step down from a switch-list avatar. */
561
+ const FACEPILE_AVATAR_SIZE = 32;
562
+ /**
563
+ * Facepile overlap. Well under Bloom's `size / 3` default: the stack draws the
564
+ * FIRST item on top, so a deep overlap would bury the trailing `+N` chip's own
565
+ * label under the avatar before it.
566
+ */
567
+ const FACEPILE_OVERLAP = 4;
568
+
569
+
570
+ /**
571
+ * `bytes` → `"11.6 GB"`. Whole plan sizes read as whole numbers (`"17 GB"`, not
572
+ * `"17.0 GB"`), and anything ≥ 100 GB drops the decimal entirely.
573
+ */
574
+ function formatStorageGb(bytes: number): string {
575
+ const gb = bytes / 1024 ** 3;
576
+ if (gb >= 100 || Number.isInteger(gb)) return `${Math.round(gb)} GB`;
577
+ return `${gb.toFixed(1)} GB`;
578
+ }
579
+
580
+ type HoverPressableProps = Omit<React.ComponentProps<typeof Pressable>, 'className'> & {
581
+ baseClassName: string;
582
+ hoverClassName: string;
583
+ };
584
+
585
+ /**
586
+ * A `Pressable` that appends a hover-tint NativeWind token while pointer-hovered.
587
+ * The Metro web pipeline here does NOT emit NativeWind `hover:` variants, so hover
588
+ * is driven by RN's cross-platform `onHoverIn`/`onHoverOut` (they fire only on web
589
+ * via react-native-web; a no-op on native) toggling a plain background token —
590
+ * the tint stays a NativeWind class, only the trigger is JS.
591
+ */
592
+ const HoverPressable: React.FC<HoverPressableProps> = ({
593
+ baseClassName,
594
+ hoverClassName,
595
+ ...rest
596
+ }) => {
597
+ const [hovered, setHovered] = useState(false);
598
+ return (
599
+ <Pressable
600
+ {...rest}
601
+ className={hovered ? `${baseClassName} ${hoverClassName}` : baseClassName}
602
+ onHoverIn={() => setHovered(true)}
603
+ onHoverOut={() => setHovered(false)}
604
+ />
605
+ );
606
+ };
607
+
608
+ /**
609
+ * The signed-in Oxy account MENU — a Google-account-menu-style full menu built
610
+ * entirely with NativeWind `className` (the dynamic per-account accent hex is
611
+ * the one inline style NativeWind can't express). Structure mirrors the
612
+ * approved demo:
613
+ * - ACCOUNT on its own distinct panel surface: a COMPACT current-account row
614
+ * (avatar + name + email + expand chevron) that toggles the switch list, a
615
+ * "Manage your Oxy account" pill, and — when expanded — the other switchable
616
+ * accounts + "Add another account" + "Manage accounts on this device".
617
+ * - OXY STORAGE: cloud + used/total + a progress bar + Upgrade / Manage chips.
618
+ * - MENU rows: Your data in Oxy · Oxy settings · Help & feedback · Sign out —
619
+ * Bloom's grouped section (`SettingsListGroup`/`SettingsListItem`), the same
620
+ * component every other SDK settings surface uses, not a local row copy.
621
+ * - FOOTER: Privacy Policy · Terms of Service.
622
+ *
623
+ * All three blocks share ONE rhythm taken from that grouped section: a 12px
624
+ * content inset, a 12px gap after the leading element, 16px between blocks, and
625
+ * a 16px trailing chevron column.
626
+ *
627
+ * Collapse state is a plain `useState` toggled in the current row's press
628
+ * handler — no effect hook, no derived-from-props sync. With only ONE account
629
+ * (nothing to switch to) the chevron is hidden and the list renders inline so
630
+ * "Add another account" stays reachable without a pointless toggle.
631
+ */
632
+ const AccountsView: React.FC<AccountsViewProps> = ({
633
+ snapshot,
634
+ theme,
635
+ t,
636
+ handlers,
637
+ storage,
638
+ menu,
639
+ }) => {
640
+ const [expanded, setExpanded] = useState(false);
641
+ // Measured natural height of the switch list, so the reveal animates to an
642
+ // exact height (and the content below reflows down smoothly) instead of a
643
+ // guessed max. The measuring wrapper is style-based, NOT className'd — on
644
+ // RN-Web `onLayout` never fires for className'd Views (see AGENTS.md).
645
+ const [listContentHeight, setListContentHeight] = useState(0);
646
+ // 0 = collapsed, 1 = expanded. Set imperatively in the toggle handler (no
647
+ // effect hook). On RN-Web there is no worklets plugin, so every shared value a
648
+ // mapper reads MUST be in its deps array or it freezes on the first frame
649
+ // (AGENTS.md "Reanimated (web)").
650
+ const listProgress = useSharedValue(0);
651
+ const listStyle = useAnimatedStyle(
652
+ () => ({ height: listProgress.value * listContentHeight, opacity: listProgress.value }),
653
+ [listProgress, listContentHeight],
654
+ );
655
+ const chevronStyle = useAnimatedStyle(
656
+ () => ({ transform: [{ rotate: `${listProgress.value * 180}deg` }] }),
657
+ [listProgress],
658
+ );
659
+ // Collapsed, the switch card is a single row and reads as a PILL; opened, it
660
+ // becomes a card holding rows and takes the grouped-section corner. The corner
661
+ // is driven off the SAME `listProgress` as the reveal — but clamped to its
662
+ // opening fraction, so it resolves early instead of trailing the rows: the
663
+ // card already reads as a card by the time they are visible. Collapsing is the
664
+ // mirror image, the pill returning over the closing tail.
665
+ const switchCardStyle = useAnimatedStyle(
666
+ () => ({
667
+ borderRadius: interpolate(
668
+ listProgress.value,
669
+ [0, SWITCH_CARD_RADIUS_SETTLE],
670
+ [SWITCH_CARD_PILL_RADIUS, SWITCH_CARD_RADIUS],
671
+ Extrapolation.CLAMP,
672
+ ),
673
+ }),
674
+ [listProgress],
675
+ );
676
+ // `CompositionBar` ships as an interactive breakdown: a selected segment
677
+ // replaces its hint line with that segment's readout. Tapping the selected one
678
+ // again clears it.
679
+ const [storageSegment, setStorageSegment] = useState<string | null>(null);
680
+ const toggleStorageSegment = useCallback(
681
+ (key: string) => setStorageSegment((previous) => (previous === key ? null : key)),
682
+ [],
683
+ );
684
+ const toggleExpanded = useCallback(() => {
685
+ const next = !expanded;
686
+ setExpanded(next);
687
+ listProgress.value = withTiming(next ? 1 : 0, { duration: 240 });
688
+ }, [expanded, listProgress]);
373
689
 
374
- const AccountsView: React.FC<AccountsViewProps> = ({ snapshot, theme, t, handlers }) => {
375
690
  if (snapshot.loading && snapshot.accounts.length === 0) {
376
691
  return (
377
- <View style={styles.centeredBlock}>
692
+ <View className="items-center justify-center gap-space-12 py-space-24">
378
693
  <MaterialCommunityIcons name="loading" size={24} color={theme.colors.textSecondary} />
379
- <Text style={[styles.mutedText, { color: theme.colors.textSecondary }]}>
380
- {t('accountSwitcher.loading') || 'Loading accounts…'}
694
+ <Text className="text-body text-text-secondary text-center">
695
+ {t('accountSwitcher.loading')}
381
696
  </Text>
382
697
  </View>
383
698
  );
384
699
  }
385
700
 
386
- return (
387
- <View style={styles.rows}>
388
- {snapshot.accounts.map((account) => (
389
- <AccountRow
390
- key={account.accountId}
391
- account={account}
392
- theme={theme}
393
- switching={snapshot.switchingAccountId === account.accountId}
394
- disabled={snapshot.switchingAccountId !== null}
395
- onPress={() => handlers.onSwitch(account.accountId)}
396
- />
397
- ))}
701
+ const switchingDisabled = snapshot.switchingAccountId !== null;
702
+ const current = snapshot.accounts.find((account) => account.isCurrent) ?? snapshot.accounts[0];
703
+ const others = current
704
+ ? snapshot.accounts.filter((account) => account.accountId !== current.accountId)
705
+ : snapshot.accounts;
706
+ const currentAccent = current
707
+ ? resolveAccentHex(current.color, theme.colors.primary)
708
+ : theme.colors.primary;
709
+ // The hero's address line under the greeting: the account's canonical @oxy.so
710
+ // email when it has one, else its normalized `@handle` (never a synthesized
711
+ // `username@oxy.so`, per the identity contract — `getNormalizedUserHandle`).
712
+ const currentAddress = current ? heroAddressLine(current) : null;
713
+ // The switch list repeats the CURRENT account (first, ringed) — unlike the old
714
+ // compact header it is not represented anywhere else once the hero moved out
715
+ // of the card, and the list is where you switch back to it.
716
+ const switchableAccounts = current ? [current, ...others] : others;
717
+ const facepile: AvatarGroupItem[] = switchableAccounts.map((account) => ({
718
+ id: account.accountId,
719
+ uri: account.avatarUrl ?? undefined,
720
+ displayName: account.displayName,
721
+ }));
722
+
723
+ // Used vs free is a two-part COMPOSITION (the parts always fill the bar), not
724
+ // a progress value — exactly what Bloom's `CompositionBar` models. Both colors
725
+ // are theme tokens, so the bar is correct in light and dark.
726
+ const storageCategories: CompositionCategory[] = storage
727
+ ? [
728
+ {
729
+ key: 'used',
730
+ name: t('accountMenu.storage.used'),
731
+ amount: storage.usedBytes,
732
+ color: theme.colors.primary,
733
+ },
734
+ {
735
+ key: 'free',
736
+ name: t('accountMenu.storage.free'),
737
+ amount: Math.max(0, storage.limitBytes - storage.usedBytes),
738
+ color: theme.colors.contrast50,
739
+ },
740
+ ]
741
+ : [];
742
+ const usageLabel = storage
743
+ ? t('accountMenu.storage.usage', {
744
+ used: formatStorageGb(storage.usedBytes),
745
+ total: formatStorageGb(storage.limitBytes),
746
+ })
747
+ : t('accountMenu.storage.unavailable');
748
+
749
+ // The switch list body, revealed under the "Switch account" row. Own markup,
750
+ // not a Bloom grouped section: this is not a list of settings rows and the
751
+ // component is not a card container. It mirrors the section's rhythm by hand —
752
+ // 12px content inset, 12px after the avatar, a hairline between rows — and
753
+ // draws those hairlines INSIDE the animated clip, so a collapsed list never
754
+ // strands one against the header row.
755
+ const listItems = (
756
+ <>
757
+ {switchableAccounts.map((account, index) => {
758
+ const accent = resolveAccentHex(account.color, theme.colors.primary);
759
+ const isSwitching = snapshot.switchingAccountId === account.accountId;
760
+ return (
761
+ <Fragment key={account.accountId}>
762
+ {index > 0 ? <View className="h-px bg-border opacity-30 ml-space-12" /> : null}
763
+ <HoverPressable
764
+ baseClassName={`flex-row items-center gap-space-12 px-space-12 py-[10px]${
765
+ switchingDisabled ? ' opacity-60' : ''
766
+ }`}
767
+ hoverClassName="bg-fill-secondary"
768
+ onPress={() => handlers.onSwitch(account.accountId)}
769
+ disabled={switchingDisabled}
770
+ accessibilityRole="button"
771
+ accessibilityLabel={account.displayName}
772
+ >
773
+ <View>
774
+ <Avatar
775
+ source={account.avatarUrl ?? undefined}
776
+ variant="thumb"
777
+ name={account.displayName}
778
+ size={SWITCH_AVATAR_SIZE}
779
+ />
780
+ {/* The accent ring is an OVERLAY: it costs the row no width, so
781
+ every avatar in the list starts on the same content line. */}
782
+ {account.isCurrent ? (
783
+ <View
784
+ style={[styles.currentAvatarRing, { borderColor: accent }]}
785
+ pointerEvents="none"
786
+ />
787
+ ) : null}
788
+ </View>
789
+ <View className="flex-1 min-w-0">
790
+ <Text className="text-body font-semibold text-text" numberOfLines={1}>
791
+ {account.displayName}
792
+ </Text>
793
+ {account.email ? (
794
+ <Text className="text-caption text-text-secondary" numberOfLines={1}>
795
+ {account.email}
796
+ </Text>
797
+ ) : null}
798
+ </View>
799
+ {isSwitching ? (
800
+ <MaterialCommunityIcons name="loading" size={20} color={accent} />
801
+ ) : null}
802
+ </HoverPressable>
803
+ </Fragment>
804
+ );
805
+ })}
398
806
 
399
- <Pressable
400
- style={[styles.addRow, { borderColor: theme.colors.border }]}
807
+ <View className="h-px bg-border opacity-30 ml-space-12" />
808
+ <AccountAffordanceRow
809
+ icon="plus"
810
+ label={t('accountMenu.addAnother')}
401
811
  onPress={handlers.onAdd}
402
- accessibilityRole="button"
403
- accessibilityLabel={t('signin.addAccountTitle') || 'Add another account'}
404
- >
405
- <View style={[styles.addBadge, { borderColor: theme.colors.border }]}>
406
- <MaterialCommunityIcons name="plus" size={20} color={theme.colors.textSecondary} />
407
- </View>
408
- <Text style={[styles.rowName, { color: theme.colors.textSecondary }]}>
409
- {t('signin.addAccountTitle') || 'Add another account'}
410
- </Text>
411
- </Pressable>
812
+ disabled={switchingDisabled}
813
+ theme={theme}
814
+ />
815
+ <View className="h-px bg-border opacity-30 ml-space-12" />
816
+ <AccountAffordanceRow
817
+ icon="account-multiple-outline"
818
+ label={t('accountSwitcher.manageOnDevice')}
819
+ onPress={handlers.onManage}
820
+ disabled={switchingDisabled}
821
+ theme={theme}
822
+ />
823
+ </>
824
+ );
825
+
826
+ const manageLabel = t('accountMenu.manage');
827
+ const switchLabel = t('accountMenu.switchAccount');
828
+
829
+ return (
830
+ <View>
831
+ {/* HERO — chrome-free and centred, in the reference's reading order:
832
+ NOTHING above the avatar (the nav bar's Oxy wordmark stands alone), the
833
+ large pressable avatar (with a camera badge to change the photo), then
834
+ the greeting, then the account address under it, then the manage action.
835
+ The nav bar above stays BRANDED (see `OxyAccountDialogScreen`). */}
836
+ <View style={styles.hero}>
837
+ {current ? (
838
+ <>
839
+ <PressableScale
840
+ onPress={handlers.onEditAvatar}
841
+ accessibilityRole="button"
842
+ accessibilityLabel={t('editProfile.changeAvatar')}
843
+ style={styles.heroAvatarPressable}
844
+ >
845
+ <Avatar
846
+ source={current.avatarUrl ?? undefined}
847
+ name={current.displayName}
848
+ size={HERO_AVATAR_SIZE}
849
+ />
850
+ <View
851
+ style={[styles.heroAvatarRing, { borderColor: currentAccent }]}
852
+ pointerEvents="none"
853
+ />
854
+ <AvatarCameraBadge />
855
+ </PressableScale>
856
+ <View style={styles.heroNameBlock}>
857
+ <Text
858
+ style={[styles.heroGreeting, { color: theme.colors.text }]}
859
+ numberOfLines={2}
860
+ >
861
+ {t('accountMenu.greeting', { name: current.displayName })}
862
+ </Text>
863
+ {currentAddress ? (
864
+ <Text
865
+ style={[styles.heroAddress, { color: theme.colors.textSecondary }]}
866
+ numberOfLines={1}
867
+ >
868
+ {currentAddress}
869
+ </Text>
870
+ ) : null}
871
+ </View>
872
+ </>
873
+ ) : null}
874
+ {/* Bloom's own compact outlined pill — `secondary` is the outlined
875
+ variant, `small` the compact height; it hugs its label instead of
876
+ spanning the surface. */}
877
+ <Button
878
+ variant="secondary"
879
+ size="small"
880
+ onPress={handlers.onManage}
881
+ accessibilityLabel={manageLabel}
882
+ >
883
+ {manageLabel}
884
+ </Button>
885
+ </View>
412
886
 
413
- <View style={styles.footerLinks}>
414
- <Pressable onPress={handlers.onManage} accessibilityRole="button">
415
- <Text style={[styles.linkText, { color: theme.colors.primary }]}>
416
- {t('accountMenu.manage') || 'Manage accounts'}
887
+ {/* SWITCH ACCOUNT — own NativeWind card, NOT a Bloom grouped section: it
888
+ is a disclosure header over an animated list, not a list of settings
889
+ rows, and the grouped section is not a bare card container. It borrows
890
+ the section's LOOK by hand — the same `card` surface, 12px content inset
891
+ and 16px gap to the next block — and its corner animates from a pill
892
+ (collapsed, a single row) to that section's 16px card corner (opened,
893
+ a card of rows) on the same `listProgress` the reveal runs on. */}
894
+ <Animated.View className="bg-fill overflow-hidden mb-space-16" style={switchCardStyle}>
895
+ <HoverPressable
896
+ baseClassName={`flex-row items-center gap-space-12 px-space-12 py-[10px] min-h-[44px]${
897
+ switchingDisabled ? ' opacity-60' : ''
898
+ }`}
899
+ hoverClassName="bg-fill-secondary"
900
+ onPress={toggleExpanded}
901
+ disabled={switchingDisabled}
902
+ accessibilityRole="button"
903
+ // The ARIA prop, not `accessibilityState`: react-native-web 0.21
904
+ // forwards only this one, and RN maps it to
905
+ // `accessibilityState.expanded` natively — so the disclosure state
906
+ // reaches assistive tech on BOTH platforms.
907
+ aria-expanded={expanded}
908
+ accessibilityLabel={switchLabel}
909
+ >
910
+ <Text className="flex-1 text-body text-text" numberOfLines={1}>
911
+ {switchLabel}
417
912
  </Text>
913
+ {/* The facepile previews who you can switch to; once the list is open
914
+ it would just restate the rows below it. */}
915
+ {expanded ? null : (
916
+ <AvatarGroup
917
+ items={facepile}
918
+ layout="stack"
919
+ size={FACEPILE_AVATAR_SIZE}
920
+ max={FACEPILE_MAX}
921
+ overlap={FACEPILE_OVERLAP}
922
+ variant="thumb"
923
+ showInitials
924
+ ringColor={theme.colors.card}
925
+ />
926
+ )}
927
+ <View style={[styles.chevronCircle, { backgroundColor: theme.colors.contrast50 }]}>
928
+ <Animated.View style={chevronStyle}>
929
+ <MaterialCommunityIcons name="chevron-down" size={20} color={theme.colors.text} />
930
+ </Animated.View>
931
+ </View>
932
+ </HoverPressable>
933
+
934
+ {/* Animated reveal: an overflow-clipped container whose height + opacity
935
+ are driven by `listProgress`; the inner style-based wrapper measures
936
+ the natural content height via `onLayout`. */}
937
+ <Animated.View
938
+ style={[styles.collapse, listStyle]}
939
+ pointerEvents={expanded ? 'auto' : 'none'}
940
+ >
941
+ <View
942
+ style={styles.collapseMeasure}
943
+ onLayout={(event) => setListContentHeight(event.nativeEvent.layout.height)}
944
+ >
945
+ <View>{listItems}</View>
946
+ </View>
947
+ </Animated.View>
948
+ </Animated.View>
949
+
950
+ {/* OXY STORAGE — own NativeWind card for the same reason: a title, a meter
951
+ and two chips are not settings rows. Its cloud sits in the same 20px
952
+ column Bloom's own rows use, so the title below lines up with the menu
953
+ titles. `CompositionBar` is consumed exactly as it ships — an
954
+ interactive breakdown at its own thickness, its hint line carrying the
955
+ used/total copy and a tapped segment revealing that segment's share. */}
956
+ <View className="bg-fill rounded-[16px] overflow-hidden mb-space-16 px-space-12 py-[10px] gap-space-12">
957
+ <View className="flex-row items-center gap-space-12 min-h-[24px]">
958
+ <View className="w-[20px] items-center">
959
+ <MaterialCommunityIcons
960
+ name="cloud-outline"
961
+ size={ROW_ICON_SIZE}
962
+ color={theme.colors.textSecondary}
963
+ />
964
+ </View>
965
+ <Text className="flex-1 text-body font-semibold text-text" numberOfLines={1}>
966
+ {t('accountMenu.storage.title')}
967
+ </Text>
968
+ </View>
969
+ <CompositionBar
970
+ categories={storageCategories}
971
+ selectedKey={storageSegment}
972
+ onSelect={toggleStorageSegment}
973
+ hintLabel={usageLabel}
974
+ formatReadout={(bytes, percent) => `${formatStorageGb(bytes)} · ${percent}%`}
975
+ />
976
+ <View className="flex-row gap-space-8">
977
+ <StorageChip label={t('accountMenu.storage.upgrade')} onPress={menu.onUpgradeStorage} />
978
+ <StorageChip label={t('accountMenu.storage.manage')} onPress={menu.onManageStorage} />
979
+ </View>
980
+ </View>
981
+
982
+ {/* MENU — the same stock grouped section. */}
983
+ <SettingsListGroup>
984
+ <SettingsListItem
985
+ icon={<MenuIcon name="tray-arrow-down" theme={theme} />}
986
+ title={t('accountMenu.data')}
987
+ onPress={menu.onOpenData}
988
+ />
989
+ <SettingsListItem
990
+ icon={<MenuIcon name="cog-outline" theme={theme} />}
991
+ title={t('accountMenu.settings')}
992
+ onPress={menu.onOpenSettings}
993
+ />
994
+ <SettingsListItem
995
+ icon={<MenuIcon name="help-circle-outline" theme={theme} />}
996
+ title={t('accountMenu.help')}
997
+ onPress={menu.onHelp}
998
+ />
999
+ <SettingsListItem
1000
+ icon={<MenuIcon name="logout" theme={theme} />}
1001
+ title={t('accountMenu.signOut')}
1002
+ onPress={menu.onSignOut}
1003
+ showChevron={false}
1004
+ />
1005
+ </SettingsListGroup>
1006
+
1007
+ {/* FOOTER. */}
1008
+ <View className="flex-row items-center justify-center gap-space-12 px-space-12 pb-space-8">
1009
+ <Pressable onPress={menu.onPrivacy} accessibilityRole="link">
1010
+ <Text className="text-bodySmall text-text-secondary">{t('accountMenu.privacy')}</Text>
1011
+ </Pressable>
1012
+ <Text className="text-bodySmall text-text-tertiary">·</Text>
1013
+ <Pressable onPress={menu.onTerms} accessibilityRole="link">
1014
+ <Text className="text-bodySmall text-text-secondary">{t('accountMenu.terms')}</Text>
418
1015
  </Pressable>
419
1016
  </View>
420
1017
  </View>
421
1018
  );
422
1019
  };
423
1020
 
1021
+ // ---------------------------------------------------------------------------
1022
+ // Account-menu row building blocks (NativeWind)
1023
+ // ---------------------------------------------------------------------------
1024
+
1025
+ /**
1026
+ * An account-list AFFORDANCE row ("Add another account", "Manage accounts on
1027
+ * this device") — a bordered circle sized to the avatar it stands in for, so its
1028
+ * label lands on the same line as every account name above it. Own markup, like
1029
+ * the account rows it closes: this list is not a Bloom grouped section.
1030
+ */
1031
+ const AccountAffordanceRow: React.FC<{
1032
+ icon: keyof typeof MaterialCommunityIcons.glyphMap;
1033
+ label: string;
1034
+ onPress: () => void;
1035
+ disabled?: boolean;
1036
+ theme: Theme;
1037
+ }> = ({ icon, label, onPress, disabled, theme }) => (
1038
+ <HoverPressable
1039
+ baseClassName={`flex-row items-center gap-space-12 px-space-12 py-[10px]${
1040
+ disabled ? ' opacity-60' : ''
1041
+ }`}
1042
+ hoverClassName="bg-fill-secondary"
1043
+ onPress={onPress}
1044
+ disabled={disabled}
1045
+ accessibilityRole="button"
1046
+ accessibilityLabel={label}
1047
+ >
1048
+ <View className="w-[36px] h-[36px] items-center justify-center rounded-radius-max border border-border">
1049
+ <MaterialCommunityIcons name={icon} size={BADGE_GLYPH_SIZE} color={theme.colors.textSecondary} />
1050
+ </View>
1051
+ <Text className="flex-1 text-body font-semibold text-text" numberOfLines={1}>
1052
+ {label}
1053
+ </Text>
1054
+ </HoverPressable>
1055
+ );
1056
+
1057
+ /**
1058
+ * The leading glyph for a grouped-section menu row, sized to Bloom's 20px icon
1059
+ * column so the icons, the storage block's cloud and every row title align.
1060
+ */
1061
+ const MenuIcon: React.FC<{
1062
+ name: keyof typeof MaterialCommunityIcons.glyphMap;
1063
+ theme: Theme;
1064
+ }> = ({ name, theme }) => (
1065
+ <MaterialCommunityIcons name={name} size={ROW_ICON_SIZE} color={theme.colors.textSecondary} />
1066
+ );
1067
+
1068
+ /** A storage action chip — a bordered pill on the sheet background. */
1069
+ const StorageChip: React.FC<{ label: string; onPress: () => void }> = ({ label, onPress }) => (
1070
+ <HoverPressable
1071
+ baseClassName="rounded-radius-max border border-border bg-bg py-[9px] px-[14px]"
1072
+ hoverClassName="bg-fill-secondary"
1073
+ onPress={onPress}
1074
+ accessibilityRole="button"
1075
+ accessibilityLabel={label}
1076
+ >
1077
+ <Text className="text-bodySmall font-semibold text-text">{label}</Text>
1078
+ </HoverPressable>
1079
+ );
1080
+
424
1081
  interface AccountRowProps {
425
1082
  account: SwitchableAccount;
426
1083
  theme: Theme;
@@ -481,9 +1138,9 @@ const AccountRow: React.FC<AccountRowProps> = ({ account, theme, switching, disa
481
1138
  };
482
1139
 
483
1140
  // ---------------------------------------------------------------------------
484
- // Sign-in view (add / signin) — NATIVE-facing today: on web the auto-start
485
- // effect above moves the view to `qr` almost immediately, so this renders
486
- // only for a brief instant there.
1141
+ // Sign-in view (add / signin) — NATIVE-facing today: on web `autoStartSignIn`
1142
+ // (fired from the subscribe pass / the add / back-to-sign-in handlers) moves the
1143
+ // view to `qr` almost immediately, so this renders only for a brief instant there.
487
1144
  // ---------------------------------------------------------------------------
488
1145
 
489
1146
  interface SignInViewProps {