@oxyhq/services 22.10.0 → 22.11.1

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