@oxyhq/services 22.10.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 (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 +54 -41
  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 +54 -42
  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 +8 -4
  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 +56 -46
  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
@@ -44,6 +44,87 @@ describe('createSurfaceNavStack', () => {
44
44
  stack.requestDismiss('again');
45
45
  expect(stack.store.getState().closeResult).toBe('done');
46
46
  });
47
+
48
+ describe('result-bearing sub-flow (morphed-in avatar picker)', () => {
49
+ it('resolves with the descendant dismiss result and pops back to the caller frame', async () => {
50
+ const stack = createSurfaceNavStack('EditProfile');
51
+ const flow = stack.beginFlow('ChangeAvatar');
52
+ expect(stack.getTop().route).toBe('ChangeAvatar');
53
+ // Drill into the crop editor within the flow, then confirm.
54
+ stack.navigate('AvatarCrop', { imageUri: 'file:///x.jpg' });
55
+ stack.resolveFlowOrDismiss({ uri: 'file:///cropped.jpg' });
56
+ await expect(flow).resolves.toEqual({ uri: 'file:///cropped.jpg' });
57
+ // Popped back to the frame that started the flow — surface NOT dismissed.
58
+ expect(stack.getTop().route).toBe('EditProfile');
59
+ expect(stack.store.getState().closing).toBe(false);
60
+ });
61
+
62
+ it('resolves undefined when the flow entry frame is backed out of', async () => {
63
+ const stack = createSurfaceNavStack('EditProfile');
64
+ const flow = stack.beginFlow('ChangeAvatar');
65
+ stack.navigate('AvatarCrop');
66
+ expect(stack.goBack()).toBe(true); // crop -> list (still in flow)
67
+ expect(stack.goBack()).toBe(true); // list -> EditProfile (cancels flow)
68
+ await expect(flow).resolves.toBeUndefined();
69
+ expect(stack.getTop().route).toBe('EditProfile');
70
+ expect(stack.store.getState().closing).toBe(false);
71
+ });
72
+
73
+ it('resolveFlowOrDismiss with NO active flow dismisses the surface (cold present)', () => {
74
+ const stack = createSurfaceNavStack('ChangeAvatar');
75
+ stack.resolveFlowOrDismiss({ removed: true });
76
+ expect(stack.store.getState().closing).toBe(true);
77
+ expect(stack.store.getState().closeResult).toEqual({ removed: true });
78
+ });
79
+
80
+ it('abandons a pending flow (undefined) when the surface is torn down', async () => {
81
+ const stack = createSurfaceNavStack('EditProfile');
82
+ const flow = stack.beginFlow('ChangeAvatar');
83
+ stack.abandonActiveFlow();
84
+ await expect(flow).resolves.toBeUndefined();
85
+ });
86
+
87
+ it('NESTS flows: the inner selector resolves first, then the outer avatar flow', async () => {
88
+ // ChangeAvatar (outer) → "My Oxy files" FileManagement (inner) → back → crop.
89
+ const stack = createSurfaceNavStack('EditProfile');
90
+ const avatarFlow = stack.beginFlow('ChangeAvatar');
91
+ const fileFlow = stack.beginFlow('FileManagement');
92
+ expect(stack.getTop().route).toBe('FileManagement');
93
+ // Pick a file → inner flow resolves, pops back to ChangeAvatar (outer still open).
94
+ stack.resolveFlowOrDismiss({ id: 'file-1' });
95
+ await expect(fileFlow).resolves.toEqual({ id: 'file-1' });
96
+ expect(stack.getTop().route).toBe('ChangeAvatar');
97
+ expect(stack.store.getState().closing).toBe(false);
98
+ // Now drill to crop and confirm → outer flow resolves, pops to EditProfile.
99
+ stack.navigate('AvatarCrop');
100
+ stack.resolveFlowOrDismiss({ uri: 'file:///c.jpg' });
101
+ await expect(avatarFlow).resolves.toEqual({ uri: 'file:///c.jpg' });
102
+ expect(stack.getTop().route).toBe('EditProfile');
103
+ });
104
+
105
+ it('cancelling the inner selector returns to the outer flow, leaving it open', async () => {
106
+ const stack = createSurfaceNavStack('EditProfile');
107
+ const avatarFlow = stack.beginFlow('ChangeAvatar');
108
+ const fileFlow = stack.beginFlow('FileManagement');
109
+ expect(stack.goBack()).toBe(true); // FileManagement -> ChangeAvatar (cancels inner)
110
+ await expect(fileFlow).resolves.toBeUndefined();
111
+ expect(stack.getTop().route).toBe('ChangeAvatar');
112
+ // The outer avatar flow is still pending.
113
+ let outerSettled = false;
114
+ void avatarFlow.then(() => { outerSettled = true; });
115
+ await Promise.resolve();
116
+ expect(outerSettled).toBe(false);
117
+ });
118
+
119
+ it('tearing down the surface abandons ALL nested flows (undefined)', async () => {
120
+ const stack = createSurfaceNavStack('EditProfile');
121
+ const outer = stack.beginFlow('ChangeAvatar');
122
+ const inner = stack.beginFlow('FileManagement');
123
+ stack.abandonActiveFlow();
124
+ await expect(inner).resolves.toBeUndefined();
125
+ await expect(outer).resolves.toBeUndefined();
126
+ });
127
+ });
47
128
  });
48
129
 
49
130
  describe('pushSurfaceBackHandler', () => {
@@ -22,7 +22,19 @@ export interface AccountDialogControls {
22
22
  close: () => void;
23
23
  }
24
24
 
25
+ /**
26
+ * Optional consumer overrides for account-dialog actions. `ProfileButton` (and
27
+ * similar hosts) register these while mounted so inbox/accounts can route
28
+ * "Manage" / "Add account" to app-local navigation instead of the SDK default.
29
+ */
30
+ export interface AccountDialogConsumerHooks {
31
+ onNavigateManage?: () => void;
32
+ onAddAccount?: () => void;
33
+ onNavigateProfile?: () => void;
34
+ }
35
+
25
36
  let controls: AccountDialogControls | null = null;
37
+ let consumerHooks: AccountDialogConsumerHooks | null = null;
26
38
  const visibilityListeners = new Set<(visible: boolean) => void>();
27
39
 
28
40
  export function registerAccountDialogControls(next: AccountDialogControls): () => void {
@@ -34,6 +46,22 @@ export function registerAccountDialogControls(next: AccountDialogControls): () =
34
46
  };
35
47
  }
36
48
 
49
+ /** Register app-local manage/add/profile handlers for the account dialog. */
50
+ export function registerAccountDialogConsumerHooks(
51
+ next: AccountDialogConsumerHooks | null,
52
+ ): () => void {
53
+ consumerHooks = next;
54
+ return () => {
55
+ if (consumerHooks === next) {
56
+ consumerHooks = null;
57
+ }
58
+ };
59
+ }
60
+
61
+ export function getAccountDialogConsumerHooks(): AccountDialogConsumerHooks | null {
62
+ return consumerHooks;
63
+ }
64
+
37
65
  /** Open the account dialog on `view` (default `accounts`). No-op before mount. */
38
66
  export function openAccountDialog(view?: AccountDialogView): void {
39
67
  controls?.open(view);
@@ -1,6 +1,6 @@
1
1
  import type { RouteName } from './routes';
2
2
  import { isValidRoute } from './routes';
3
- import { getSurfacePresentation } from './surfaceRegistry';
3
+ import { getSurfaceConfig } from './surfaceRegistry';
4
4
  import { closeAllRouteSurfaces, presentRoute, topRouteSurface } from './surfaces';
5
5
 
6
6
  /**
@@ -16,11 +16,10 @@ import { closeAllRouteSurfaces, presentRoute, topRouteSurface } from './surfaces
16
16
  */
17
17
 
18
18
  /**
19
- * Open a bottom-sheet route. If the top-most active surface hosts the SAME
20
- * presentation (the common all-sheets case) the route is drilled into it; a route
21
- * with a different presentation (the image picker's full-bleed surface) is
22
- * presented as a NEW surface on top. Opening with no active surface presents the
23
- * first one.
19
+ * Open a bottom-sheet route. By DEFAULT it drills into the top-most active
20
+ * surface morphing it in place (every screen morphs). A NEW surface is stacked
21
+ * on top only when the target route declares `stacks` (reserved for genuine
22
+ * overlays none today). Opening with no active surface presents the first one.
24
23
  *
25
24
  * `fullScreen` is accepted for signature compatibility and ignored — a route's
26
25
  * surface is now derived from its registry config, not a per-call flag.
@@ -39,7 +38,7 @@ export const showBottomSheet = (
39
38
  }
40
39
 
41
40
  const top = topRouteSurface();
42
- if (top && top.presentation === getSurfacePresentation(screen, props)) {
41
+ if (top && !getSurfaceConfig(screen, props).stacks) {
43
42
  top.navigate(screen, props);
44
43
  } else {
45
44
  presentRoute(screen, props);
@@ -39,7 +39,8 @@ export type RouteName =
39
39
  | 'CreateAccount' // Create a new account (organization / project / bot)
40
40
  | 'AccountMembers' // Manage an account's members (invite / roles / transfer)
41
41
  | 'AccountSettings' // Per-account profile edit + members + danger zone
42
- | 'AvatarCrop' // Square-crop editor presented before avatar upload
42
+ | 'ChangeAvatar' // Profile-picture source list the ONE entry into changing an avatar
43
+ | 'AvatarCrop' // Square-crop editor, reached by navigating within the ChangeAvatar surface
43
44
  | 'Notifications' // Per-channel notification preferences
44
45
  | 'ConnectedApps' // OAuth-authorized third-party apps the user can revoke
45
46
  | 'Preferences' // General user preferences (theme, reduce-motion, etc.)
@@ -83,6 +84,7 @@ const screenLoaders: Record<RouteName, () => ComponentType<BaseScreenProps>> = {
83
84
  CreateAccount: () => require('../screens/CreateAccountScreen').default,
84
85
  AccountMembers: () => require('../screens/AccountMembersScreen').default,
85
86
  AccountSettings: () => require('../screens/AccountSettingsScreen').default,
87
+ ChangeAvatar: () => require('../screens/ChangeAvatarScreen').default,
86
88
  AvatarCrop: () => require('../screens/AvatarCropScreen').default,
87
89
  Notifications: () => require('../screens/NotificationsScreen').default,
88
90
  ConnectedApps: () => require('../screens/ConnectedAppsScreen').default,
@@ -48,6 +48,27 @@ export interface SurfaceNavStack {
48
48
  setStep(step: number): void;
49
49
  /** Request dismissal of the whole surface, resolving its promise with `result`. */
50
50
  requestDismiss(result?: unknown): void;
51
+ /**
52
+ * Begin a result-bearing SUB-FLOW inside this surface: push `route` as a frame
53
+ * and return a promise that settles when the flow finishes — a descendant's
54
+ * `dismiss(result)` resolves it with `result`, backing out of the flow's entry
55
+ * frame resolves it with `undefined` (cancelled) — popping the surface back to
56
+ * the frame that started the flow WITHOUT dismissing it. This is how a screen
57
+ * already living inside a surface (EditProfile, ManageAccount, ChangeAvatar)
58
+ * opens the avatar picker / media selector as a MORPH instead of a stacked
59
+ * surface while still awaiting its result. Flows NEST (ChangeAvatar → the "My
60
+ * Oxy files" selector → back), maintained as a stack.
61
+ */
62
+ beginFlow(route: RouteName, props?: Record<string, unknown>): Promise<unknown>;
63
+ /**
64
+ * Resolve the INNERMOST active sub-flow with `result` and pop back to its entry
65
+ * (the frame that called {@link beginFlow}), leaving the surface open. With NO
66
+ * active flow this falls back to {@link requestDismiss} — so a screen presented
67
+ * as its OWN surface still dismisses it. Wired to every screen's `dismiss` prop.
68
+ */
69
+ resolveFlowOrDismiss(result?: unknown): void;
70
+ /** Settle EVERY still-pending sub-flow with `undefined` (the surface is going away). */
71
+ abandonActiveFlow(): void;
51
72
  /** The current (top) frame. */
52
73
  getTop(): NavFrame;
53
74
  }
@@ -73,9 +94,41 @@ export function createSurfaceNavStack(
73
94
  return frames[frames.length - 1];
74
95
  };
75
96
 
97
+ // Result-bearing sub-flows currently running in this surface (the morphed-in
98
+ // avatar picker, and — NESTED within it — the "My Oxy files" media selector).
99
+ // A STACK: flows nest (ChangeAvatar → FileManagement → back to ChangeAvatar).
100
+ // Held OUTSIDE the store (resolvers are functions; flow presence must not
101
+ // re-render frames). Each flow's `returnLength` is the frame count BEFORE its
102
+ // entry frame was pushed, so settling pops back to exactly the frame that
103
+ // started it. `flowStack` is ordered outer → inner; the top is the innermost.
104
+ const flowStack: { returnLength: number; resolve: (result: unknown) => void }[] = [];
105
+
106
+ const requestDismiss = (result?: unknown): void => {
107
+ // Dismissing the whole surface abandons EVERY pending sub-flow — settle each
108
+ // promise so an awaiting caller (the avatar picker) never hangs.
109
+ while (flowStack.length) flowStack.pop()?.resolve(undefined);
110
+ if (store.getState().closing) return;
111
+ store.setState({ closing: true, closeResult: result });
112
+ };
113
+
114
+ const goBack = (): boolean => {
115
+ const { frames } = store.getState();
116
+ if (frames.length <= 1) return false;
117
+ const nextLength = frames.length - 1;
118
+ store.setState({ frames: frames.slice(0, -1) });
119
+ // Backing out past a sub-flow's entry frame cancels it (resolve undefined).
120
+ // A single pop crosses at most one boundary, but loop for safety.
121
+ while (flowStack.length && nextLength <= flowStack[flowStack.length - 1].returnLength) {
122
+ flowStack.pop()?.resolve(undefined);
123
+ }
124
+ return true;
125
+ };
126
+
76
127
  return {
77
128
  store,
78
129
  getTop,
130
+ requestDismiss,
131
+ goBack,
79
132
  navigate(nextRoute, nextProps) {
80
133
  store.setState((state) => ({ frames: [...state.frames, makeFrame(nextRoute, nextProps)] }));
81
134
  },
@@ -84,12 +137,6 @@ export function createSurfaceNavStack(
84
137
  frames: [...state.frames.slice(0, -1), makeFrame(nextRoute, nextProps)],
85
138
  }));
86
139
  },
87
- goBack() {
88
- const { frames } = store.getState();
89
- if (frames.length <= 1) return false;
90
- store.setState({ frames: frames.slice(0, -1) });
91
- return true;
92
- },
93
140
  canGoBack() {
94
141
  const { frames } = store.getState();
95
142
  return frames.length > 1 || (frames[frames.length - 1]?.step ?? 0) > 0;
@@ -102,9 +149,25 @@ export function createSurfaceNavStack(
102
149
  return { frames };
103
150
  });
104
151
  },
105
- requestDismiss(result) {
106
- if (store.getState().closing) return;
107
- store.setState({ closing: true, closeResult: result });
152
+ beginFlow(nextRoute, nextProps) {
153
+ const returnLength = store.getState().frames.length;
154
+ store.setState((state) => ({ frames: [...state.frames, makeFrame(nextRoute, nextProps)] }));
155
+ return new Promise<unknown>((resolve) => {
156
+ flowStack.push({ returnLength, resolve });
157
+ });
158
+ },
159
+ resolveFlowOrDismiss(result) {
160
+ const flow = flowStack.pop();
161
+ if (!flow) {
162
+ // No flow → this screen owns its surface; dismiss it as before.
163
+ requestDismiss(result);
164
+ return;
165
+ }
166
+ store.setState((state) => ({ frames: state.frames.slice(0, flow.returnLength) }));
167
+ flow.resolve(result);
168
+ },
169
+ abandonActiveFlow() {
170
+ while (flowStack.length) flowStack.pop()?.resolve(undefined);
108
171
  },
109
172
  };
110
173
  }
@@ -2,6 +2,7 @@ import type { ReactNode } from 'react';
2
2
  import type { AccountDialogView, FileMetadata } from '@oxyhq/core';
3
3
  import type { RouteName } from './routes';
4
4
  import type { AvatarCropResult } from '../screens/AvatarCropScreen';
5
+ import type { AvatarRemovalResult } from '../screens/ChangeAvatarScreen';
5
6
 
6
7
  /**
7
8
  * The SDK's typed surface registry — the contract layer the SDK stacks on top of
@@ -60,7 +61,17 @@ export interface SurfaceRegistry {
60
61
  CreateAccount: SurfaceRoute;
61
62
  AccountMembers: SurfaceRoute;
62
63
  AccountSettings: SurfaceRoute;
63
- /** Square-crop editor. Dismissed with the cropped {@link AvatarCropResult}. */
64
+ /**
65
+ * Profile-picture source list — the ONE entry into changing an avatar. Every
66
+ * source that yields an image navigates WITHIN this surface to `AvatarCrop`
67
+ * (so the panel morphs), and the crop's own dismissal resolves this surface.
68
+ * Hence the union: a confirmed crop, or the user removing their photo.
69
+ */
70
+ ChangeAvatar: SurfaceRoute<Record<string, unknown>, AvatarCropResult | AvatarRemovalResult>;
71
+ /**
72
+ * Square-crop editor. Dismissed with the cropped {@link AvatarCropResult}.
73
+ * Reached only by navigating within a `ChangeAvatar` surface.
74
+ */
64
75
  AvatarCrop: SurfaceRoute<Record<string, unknown>, AvatarCropResult>;
65
76
  Notifications: SurfaceRoute;
66
77
  ConnectedApps: SurfaceRoute;
@@ -91,15 +102,18 @@ export type SurfaceResult<K extends RouteName> = SurfaceRegistry[K]['result'];
91
102
  * How a surface renders — the SDK's presentation taxonomy. Each value maps to a
92
103
  * concrete Bloom `Dialog` placement/chrome in `surfaces.ts`:
93
104
  *
94
- * - `'sheet'` → responsive `{ base: 'bottom', md: 'center' }` (the default:
95
- * a bottom sheet on narrow viewports, a centered card on wide).
96
- * - `'center'` → a plain centered modal at every width.
105
+ * - `'sheet'` → responsive `{ base: 'bottom', md: 'center' }` (the default,
106
+ * and since every screen morphs the presentation of EVERY
107
+ * route today: a bottom sheet on narrow, a centered card wide).
108
+ * - `'center'` → a plain centered modal at every width. Currently unused.
97
109
  * - `'drawer'` → responsive `{ base: 'bottom', md: 'left' }` side drawer.
98
- * - `'fullScreen'` → approximated with the shared `Dialog`: a full-height sheet /
99
- * large centered card, flush (`contentPadding: 0`) content, a
100
- * black canvas and programmatic-only dismiss (the flagship
101
- * image picker). A real Bloom `'fullScreen'` placement is a
102
- * follow-up if the approximation reads wrong on device.
110
+ * Currently unused.
111
+ * - `'fullScreen'` a flush black-canvas surface (`contentPadding: 0`,
112
+ * programmatic-only dismiss). Currently unused: the flagship
113
+ * photo picker now MORPHS in place as a `sheet` (it paints its
114
+ * own black canvas + bar inside the themed panel), so nothing
115
+ * needs a stacked full-bleed surface. Retained for a future
116
+ * route that genuinely must be full-bleed.
103
117
  */
104
118
  export type SurfacePresentation = 'sheet' | 'center' | 'drawer' | 'fullScreen';
105
119
 
@@ -123,6 +137,47 @@ export interface SurfaceRouteConfig {
123
137
  * wrap it in a ScrollView. Threaded onto Bloom's `Dialog` via `bloomOptionsFor`.
124
138
  */
125
139
  scrollable: boolean;
140
+ /**
141
+ * Whether the surface MORPHS when this route is navigated to WITHIN it — the
142
+ * panel animates from the outgoing frame's size to this one's instead of
143
+ * hard-cutting (the in-place NAV-WITHIN size animation). `true` for every
144
+ * ordinary route screen; a wizard step swap counts as a frame here too.
145
+ *
146
+ * Distinct from {@link stacks}: `morph` tunes the size animation of an IN-PLACE
147
+ * frame swap; `stacks` decides whether the frame lands in place at all or opens
148
+ * a new surface. A stacked surface can still morph between ITS OWN frames.
149
+ */
150
+ morph: boolean;
151
+ /**
152
+ * An EXPLICIT target size the panel MORPHS to for this route, instead of the
153
+ * measured natural height / the surface width. This is how an own-scroller frame
154
+ * (its content owns its own scroll, so the panel can't measure it) still GROWS
155
+ * its container to a large declared size — the panel animates UP to it on entry
156
+ * and back DOWN on exit while the frame's inner list scrolls within. `heightRatio`
157
+ * is a fraction of the viewport height (clamped there); `maxWidth` (px) widens the
158
+ * centered card beyond the ordinary sheet. Omit for the normal measured behaviour.
159
+ */
160
+ frameSize?: { heightRatio?: number; maxWidth?: number };
161
+ /**
162
+ * Whether navigating TO this route from INSIDE an existing surface opens a NEW
163
+ * stacked surface (its own backdrop + entry animation — the DEPTH axis) instead
164
+ * of morphing in place within the current one (the NAV-WITHIN axis).
165
+ *
166
+ * `false` (the DEFAULT) — morph in place: the route is pushed as a frame in the
167
+ * host surface's nav stack and the panel reshapes from the previous frame to it
168
+ * (size-animated per {@link morph}). Every ordinary screen. This is what makes
169
+ * morph the default: a drill-in navigates WITHIN unless the target opts out.
170
+ *
171
+ * `true` — the route's chrome is fundamentally incompatible with morphing into
172
+ * a host, so it must own its own surface: the full-bleed `fullScreen` image
173
+ * picker (black canvas, flush content, programmatic-only dismiss). Presented on
174
+ * top; dismissing it unwinds back to the surface that opened it.
175
+ *
176
+ * NOTE: the DEPTH `present` / `presentDetached` APIs ALWAYS open a new surface
177
+ * regardless of this flag — `stacks` only governs the in-surface drill-in
178
+ * (`navigate` / `showBottomSheet`) decision in `navigateWithinOrPresent`.
179
+ */
180
+ stacks: boolean;
126
181
  /**
127
182
  * Whether the surface renders the Dialog's OWN navigation header (sticky
128
183
  * gradient nav bar + large collapsing title over the surface's scroll content).
@@ -145,13 +200,14 @@ const DEFAULT_SURFACE_CONFIG: SurfaceRouteConfig = {
145
200
  presentation: 'sheet',
146
201
  scrollable: true,
147
202
  header: true,
203
+ morph: true,
204
+ stacks: false,
148
205
  manualActivation: true,
149
206
  dynamicBackdrop: true,
150
207
  };
151
208
 
152
209
  /**
153
210
  * Routes that render NO Dialog nav header — they own their chrome:
154
- * - `AvatarCrop` — its own translucent Cancel / title / Done top bar.
155
211
  * - `PaymentGateway` — the payment surface owns its controls.
156
212
  * - `WelcomeNewUser` — a full-bleed onboarding wizard with its own step chrome.
157
213
  * - `Profile` — a full profile view, no nav-header chrome.
@@ -160,9 +216,15 @@ const DEFAULT_SURFACE_CONFIG: SurfaceRouteConfig = {
160
216
  * `AccountDialog` used to be here — it now uses the SHARED Dialog nav header like
161
217
  * every other screen (its per-view title/subtitle + view-back go through
162
218
  * `useSurfaceHeader`), so the account/sign-in surface no longer feels bespoke.
219
+ *
220
+ * `AvatarCrop` used to be here too, for its own translucent Cancel/title/Done
221
+ * bar. It is now reached ONLY by navigating within a `ChangeAvatar` surface, and
222
+ * the Dialog's `header` is fixed for a surface's whole life — a headerless frame
223
+ * inside a header-mode surface would stack two bars. So the crop declares its
224
+ * title + its "Use photo" action through `useSurfaceHeader` like every other
225
+ * screen, and keeps only its dark crop stage.
163
226
  */
164
227
  const HEADERLESS_ROUTES: ReadonlySet<RouteName> = new Set<RouteName>([
165
- 'AvatarCrop',
166
228
  'PaymentGateway',
167
229
  'WelcomeNewUser',
168
230
  'Profile',
@@ -209,18 +271,30 @@ const OWN_SCROLL_CONTAINER_ROUTES: ReadonlySet<RouteName> = new Set<RouteName>([
209
271
  ]);
210
272
 
211
273
  /**
212
- * Resolve the surface configuration for a route + props. Defaults to the
213
- * responsive sheet; the image-only FileManagement picker upgrades to a full-bleed
214
- * `'fullScreen'` surface, and every route that owns its own scroll container is
215
- * marked `scrollable: false`.
274
+ * Resolve the surface configuration for a route + props. Every route defaults to
275
+ * the responsive sheet and MORPHS in place when navigated to from within a surface
276
+ * (no route stacks genuine overlays are Bloom-raw `surfaces.present`/`confirm`
277
+ * calls, outside this registry). The image-only FileManagement picker is a normal
278
+ * sheet that owns its own scroll + translucent bar (no Dialog nav header); every
279
+ * other own-scroller is marked `scrollable: false`.
216
280
  */
217
281
  export const getSurfaceConfig = (
218
282
  route: RouteName,
219
283
  props: Record<string, unknown>,
220
284
  ): SurfaceRouteConfig => {
221
285
  if (route === 'FileManagement' && isFileManagementImageOnlyPicker(props)) {
222
- // The full-bleed image picker owns its own translucent top bar no nav header.
223
- return { ...DEFAULT_SURFACE_CONFIG, presentation: 'fullScreen', scrollable: false, header: false };
286
+ // The flagship photo picker MORPHS in place like every other screen. It is an
287
+ // own-scroller (`PhotoPickerView`'s FlatList) that paints its OWN full-bleed
288
+ // black canvas + translucent top bar INSIDE the themed panel, so it takes no
289
+ // Dialog nav header. It needs ROOM for the photo grid, so it declares an
290
+ // explicit LARGE morph target — the panel grows UP to a near-full-height,
291
+ // wider card on entry (and back down on pick→crop), the grid scrolling within.
292
+ return {
293
+ ...DEFAULT_SURFACE_CONFIG,
294
+ scrollable: false,
295
+ header: false,
296
+ frameSize: { heightRatio: 0.9, maxWidth: 640 },
297
+ };
224
298
  }
225
299
  if (HEADERLESS_ROUTES.has(route)) {
226
300
  return { ...DEFAULT_SURFACE_CONFIG, header: false };