@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.
- package/lib/commonjs/ui/components/AvatarCameraBadge.js +42 -0
- package/lib/commonjs/ui/components/AvatarCameraBadge.js.map +1 -0
- package/lib/commonjs/ui/components/OxyAccountDialogScreen.js +41 -19
- package/lib/commonjs/ui/components/OxyAccountDialogScreen.js.map +1 -1
- package/lib/commonjs/ui/components/OxyAuthChooser.js +640 -168
- package/lib/commonjs/ui/components/OxyAuthChooser.js.map +1 -1
- package/lib/commonjs/ui/components/ProfileButton.js +14 -0
- package/lib/commonjs/ui/components/ProfileButton.js.map +1 -1
- package/lib/commonjs/ui/components/ProfileSummaryCard.js +3 -23
- package/lib/commonjs/ui/components/ProfileSummaryCard.js.map +1 -1
- package/lib/commonjs/ui/components/SurfaceScreen.js +41 -5
- package/lib/commonjs/ui/components/SurfaceScreen.js.map +1 -1
- package/lib/commonjs/ui/components/oxyAuthChooserStyles.js +78 -26
- package/lib/commonjs/ui/components/oxyAuthChooserStyles.js.map +1 -1
- package/lib/commonjs/ui/components/photogrid/JustifiedPhotoGrid.js +83 -23
- package/lib/commonjs/ui/components/photogrid/JustifiedPhotoGrid.js.map +1 -1
- package/lib/commonjs/ui/context/OxyContext.js +73 -37
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/queryKeys.js +18 -1
- package/lib/commonjs/ui/hooks/queries/queryKeys.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/useFileQueries.js +129 -0
- package/lib/commonjs/ui/hooks/queries/useFileQueries.js.map +1 -0
- package/lib/commonjs/ui/hooks/useAvatarPicker.js +36 -48
- package/lib/commonjs/ui/hooks/useAvatarPicker.js.map +1 -1
- package/lib/commonjs/ui/hooks/useReduceMotion.js +57 -0
- package/lib/commonjs/ui/hooks/useReduceMotion.js.map +1 -0
- package/lib/commonjs/ui/hooks/useSurfaceHeader.js +1 -1
- package/lib/commonjs/ui/hooks/useSurfaceHeader.js.map +1 -1
- package/lib/commonjs/ui/navigation/accountDialogManager.js +22 -0
- package/lib/commonjs/ui/navigation/accountDialogManager.js.map +1 -1
- package/lib/commonjs/ui/navigation/bottomSheetManager.js +5 -6
- package/lib/commonjs/ui/navigation/bottomSheetManager.js.map +1 -1
- package/lib/commonjs/ui/navigation/routes.js +1 -0
- package/lib/commonjs/ui/navigation/routes.js.map +1 -1
- package/lib/commonjs/ui/navigation/surfaceNavStack.js +62 -15
- package/lib/commonjs/ui/navigation/surfaceNavStack.js.map +1 -1
- package/lib/commonjs/ui/navigation/surfaceRegistry.js +38 -17
- package/lib/commonjs/ui/navigation/surfaceRegistry.js.map +1 -1
- package/lib/commonjs/ui/navigation/surfaces.js +98 -21
- package/lib/commonjs/ui/navigation/surfaces.js.map +1 -1
- package/lib/commonjs/ui/screens/AvatarCropScreen.js +281 -279
- package/lib/commonjs/ui/screens/AvatarCropScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ChangeAvatarScreen.js +301 -0
- package/lib/commonjs/ui/screens/ChangeAvatarScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/FileManagementScreen.js +194 -431
- package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +16 -48
- package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/fileManagement/FileLibraryError.js +63 -0
- package/lib/commonjs/ui/screens/fileManagement/FileLibraryError.js.map +1 -0
- package/lib/commonjs/ui/screens/fileManagement/PhotoPickerSection.js +54 -41
- package/lib/commonjs/ui/screens/fileManagement/PhotoPickerSection.js.map +1 -1
- package/lib/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.js +44 -81
- package/lib/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.js.map +1 -1
- package/lib/commonjs/ui/stores/resetSessionScopedStores.js +8 -3
- package/lib/commonjs/ui/stores/resetSessionScopedStores.js.map +1 -1
- package/lib/commonjs/ui/utils/avatarUtils.js +11 -2
- package/lib/commonjs/ui/utils/avatarUtils.js.map +1 -1
- package/lib/commonjs/ui/utils/fileManagement.js +0 -79
- package/lib/commonjs/ui/utils/fileManagement.js.map +1 -1
- package/lib/module/ui/components/AvatarCameraBadge.js +40 -0
- package/lib/module/ui/components/AvatarCameraBadge.js.map +1 -0
- package/lib/module/ui/components/OxyAccountDialogScreen.js +41 -19
- package/lib/module/ui/components/OxyAccountDialogScreen.js.map +1 -1
- package/lib/module/ui/components/OxyAuthChooser.js +642 -171
- package/lib/module/ui/components/OxyAuthChooser.js.map +1 -1
- package/lib/module/ui/components/ProfileButton.js +15 -1
- package/lib/module/ui/components/ProfileButton.js.map +1 -1
- package/lib/module/ui/components/ProfileSummaryCard.js +2 -23
- package/lib/module/ui/components/ProfileSummaryCard.js.map +1 -1
- package/lib/module/ui/components/SurfaceScreen.js +43 -7
- package/lib/module/ui/components/SurfaceScreen.js.map +1 -1
- package/lib/module/ui/components/oxyAuthChooserStyles.js +78 -26
- package/lib/module/ui/components/oxyAuthChooserStyles.js.map +1 -1
- package/lib/module/ui/components/photogrid/JustifiedPhotoGrid.js +83 -25
- package/lib/module/ui/components/photogrid/JustifiedPhotoGrid.js.map +1 -1
- package/lib/module/ui/context/OxyContext.js +74 -38
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/hooks/queries/queryKeys.js +16 -0
- package/lib/module/ui/hooks/queries/queryKeys.js.map +1 -1
- package/lib/module/ui/hooks/queries/useFileQueries.js +120 -0
- package/lib/module/ui/hooks/queries/useFileQueries.js.map +1 -0
- package/lib/module/ui/hooks/useAvatarPicker.js +37 -49
- package/lib/module/ui/hooks/useAvatarPicker.js.map +1 -1
- package/lib/module/ui/hooks/useReduceMotion.js +53 -0
- package/lib/module/ui/hooks/useReduceMotion.js.map +1 -0
- package/lib/module/ui/hooks/useSurfaceHeader.js +1 -1
- package/lib/module/ui/hooks/useSurfaceHeader.js.map +1 -1
- package/lib/module/ui/navigation/accountDialogManager.js +20 -0
- package/lib/module/ui/navigation/accountDialogManager.js.map +1 -1
- package/lib/module/ui/navigation/bottomSheetManager.js +6 -7
- package/lib/module/ui/navigation/bottomSheetManager.js.map +1 -1
- package/lib/module/ui/navigation/routes.js +1 -0
- package/lib/module/ui/navigation/routes.js.map +1 -1
- package/lib/module/ui/navigation/surfaceNavStack.js +62 -15
- package/lib/module/ui/navigation/surfaceNavStack.js.map +1 -1
- package/lib/module/ui/navigation/surfaceRegistry.js +38 -17
- package/lib/module/ui/navigation/surfaceRegistry.js.map +1 -1
- package/lib/module/ui/navigation/surfaces.js +97 -22
- package/lib/module/ui/navigation/surfaces.js.map +1 -1
- package/lib/module/ui/screens/AvatarCropScreen.js +283 -281
- package/lib/module/ui/screens/AvatarCropScreen.js.map +1 -1
- package/lib/module/ui/screens/ChangeAvatarScreen.js +298 -0
- package/lib/module/ui/screens/ChangeAvatarScreen.js.map +1 -0
- package/lib/module/ui/screens/FileManagementScreen.js +196 -433
- package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/module/ui/screens/WelcomeNewUserScreen.js +17 -49
- package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -1
- package/lib/module/ui/screens/fileManagement/FileLibraryError.js +59 -0
- package/lib/module/ui/screens/fileManagement/FileLibraryError.js.map +1 -0
- package/lib/module/ui/screens/fileManagement/PhotoPickerSection.js +54 -42
- package/lib/module/ui/screens/fileManagement/PhotoPickerSection.js.map +1 -1
- package/lib/module/ui/screens/fileManagement/hooks/useFileUploadState.js +45 -81
- package/lib/module/ui/screens/fileManagement/hooks/useFileUploadState.js.map +1 -1
- package/lib/module/ui/stores/resetSessionScopedStores.js +8 -3
- package/lib/module/ui/stores/resetSessionScopedStores.js.map +1 -1
- package/lib/module/ui/utils/avatarUtils.js +11 -2
- package/lib/module/ui/utils/avatarUtils.js.map +1 -1
- package/lib/module/ui/utils/fileManagement.js +0 -78
- package/lib/module/ui/utils/fileManagement.js.map +1 -1
- package/lib/typescript/commonjs/ui/components/AvatarCameraBadge.d.ts +4 -0
- package/lib/typescript/commonjs/ui/components/AvatarCameraBadge.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/OxyAccountDialogScreen.d.ts +2 -1
- package/lib/typescript/commonjs/ui/components/OxyAccountDialogScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/OxyAuthChooser.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/ProfileSummaryCard.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/SurfaceScreen.d.ts +1 -4
- package/lib/typescript/commonjs/ui/components/SurfaceScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/oxyAuthChooserStyles.d.ts +71 -19
- package/lib/typescript/commonjs/ui/components/oxyAuthChooserStyles.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/photogrid/JustifiedPhotoGrid.d.ts +10 -8
- package/lib/typescript/commonjs/ui/components/photogrid/JustifiedPhotoGrid.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/queries/queryKeys.d.ts +9 -0
- package/lib/typescript/commonjs/ui/hooks/queries/queryKeys.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/queries/useFileQueries.d.ts +50 -0
- package/lib/typescript/commonjs/ui/hooks/queries/useFileQueries.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/hooks/useAvatarPicker.d.ts +15 -10
- package/lib/typescript/commonjs/ui/hooks/useAvatarPicker.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useReduceMotion.d.ts +14 -0
- package/lib/typescript/commonjs/ui/hooks/useReduceMotion.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/hooks/useSurfaceHeader.d.ts +1 -1
- package/lib/typescript/commonjs/ui/hooks/useSurfaceHeader.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/navigation/accountDialogManager.d.ts +13 -0
- package/lib/typescript/commonjs/ui/navigation/accountDialogManager.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/navigation/bottomSheetManager.d.ts +4 -5
- package/lib/typescript/commonjs/ui/navigation/bottomSheetManager.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/navigation/routes.d.ts +1 -1
- package/lib/typescript/commonjs/ui/navigation/routes.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/navigation/surfaceNavStack.d.ts +21 -0
- package/lib/typescript/commonjs/ui/navigation/surfaceNavStack.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/navigation/surfaceRegistry.d.ts +73 -13
- package/lib/typescript/commonjs/ui/navigation/surfaceRegistry.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/navigation/surfaces.d.ts +42 -11
- package/lib/typescript/commonjs/ui/navigation/surfaces.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/AvatarCropScreen.d.ts +18 -5
- package/lib/typescript/commonjs/ui/screens/AvatarCropScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/ChangeAvatarScreen.d.ts +34 -0
- package/lib/typescript/commonjs/ui/screens/ChangeAvatarScreen.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/FileManagementScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/fileManagement/FileLibraryError.d.ts +23 -0
- package/lib/typescript/commonjs/ui/screens/fileManagement/FileLibraryError.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/fileManagement/PhotoPickerSection.d.ts +4 -0
- package/lib/typescript/commonjs/ui/screens/fileManagement/PhotoPickerSection.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.d.ts +10 -2
- package/lib/typescript/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/stores/resetSessionScopedStores.d.ts +8 -1
- package/lib/typescript/commonjs/ui/stores/resetSessionScopedStores.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/types/navigation.d.ts +2 -0
- package/lib/typescript/commonjs/ui/types/navigation.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/utils/avatarUtils.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/utils/fileManagement.d.ts +0 -48
- package/lib/typescript/commonjs/ui/utils/fileManagement.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/AvatarCameraBadge.d.ts +4 -0
- package/lib/typescript/module/ui/components/AvatarCameraBadge.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/OxyAccountDialogScreen.d.ts +2 -1
- package/lib/typescript/module/ui/components/OxyAccountDialogScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/OxyAuthChooser.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/ProfileButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/ProfileSummaryCard.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/SurfaceScreen.d.ts +1 -4
- package/lib/typescript/module/ui/components/SurfaceScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/oxyAuthChooserStyles.d.ts +71 -19
- package/lib/typescript/module/ui/components/oxyAuthChooserStyles.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/photogrid/JustifiedPhotoGrid.d.ts +10 -8
- package/lib/typescript/module/ui/components/photogrid/JustifiedPhotoGrid.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/queries/queryKeys.d.ts +9 -0
- package/lib/typescript/module/ui/hooks/queries/queryKeys.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/queries/useFileQueries.d.ts +50 -0
- package/lib/typescript/module/ui/hooks/queries/useFileQueries.d.ts.map +1 -0
- package/lib/typescript/module/ui/hooks/useAvatarPicker.d.ts +15 -10
- package/lib/typescript/module/ui/hooks/useAvatarPicker.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useReduceMotion.d.ts +14 -0
- package/lib/typescript/module/ui/hooks/useReduceMotion.d.ts.map +1 -0
- package/lib/typescript/module/ui/hooks/useSurfaceHeader.d.ts +1 -1
- package/lib/typescript/module/ui/hooks/useSurfaceHeader.d.ts.map +1 -1
- package/lib/typescript/module/ui/navigation/accountDialogManager.d.ts +13 -0
- package/lib/typescript/module/ui/navigation/accountDialogManager.d.ts.map +1 -1
- package/lib/typescript/module/ui/navigation/bottomSheetManager.d.ts +4 -5
- package/lib/typescript/module/ui/navigation/bottomSheetManager.d.ts.map +1 -1
- package/lib/typescript/module/ui/navigation/routes.d.ts +1 -1
- package/lib/typescript/module/ui/navigation/routes.d.ts.map +1 -1
- package/lib/typescript/module/ui/navigation/surfaceNavStack.d.ts +21 -0
- package/lib/typescript/module/ui/navigation/surfaceNavStack.d.ts.map +1 -1
- package/lib/typescript/module/ui/navigation/surfaceRegistry.d.ts +73 -13
- package/lib/typescript/module/ui/navigation/surfaceRegistry.d.ts.map +1 -1
- package/lib/typescript/module/ui/navigation/surfaces.d.ts +42 -11
- package/lib/typescript/module/ui/navigation/surfaces.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/AvatarCropScreen.d.ts +18 -5
- package/lib/typescript/module/ui/screens/AvatarCropScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/ChangeAvatarScreen.d.ts +34 -0
- package/lib/typescript/module/ui/screens/ChangeAvatarScreen.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/FileManagementScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/fileManagement/FileLibraryError.d.ts +23 -0
- package/lib/typescript/module/ui/screens/fileManagement/FileLibraryError.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/fileManagement/PhotoPickerSection.d.ts +4 -0
- package/lib/typescript/module/ui/screens/fileManagement/PhotoPickerSection.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/fileManagement/hooks/useFileUploadState.d.ts +10 -2
- package/lib/typescript/module/ui/screens/fileManagement/hooks/useFileUploadState.d.ts.map +1 -1
- package/lib/typescript/module/ui/stores/resetSessionScopedStores.d.ts +8 -1
- package/lib/typescript/module/ui/stores/resetSessionScopedStores.d.ts.map +1 -1
- package/lib/typescript/module/ui/types/navigation.d.ts +2 -0
- package/lib/typescript/module/ui/types/navigation.d.ts.map +1 -1
- package/lib/typescript/module/ui/utils/avatarUtils.d.ts.map +1 -1
- package/lib/typescript/module/ui/utils/fileManagement.d.ts +0 -48
- package/lib/typescript/module/ui/utils/fileManagement.d.ts.map +1 -1
- package/package.json +8 -4
- package/src/ui/components/AvatarCameraBadge.tsx +35 -0
- package/src/ui/components/OxyAccountDialogScreen.tsx +38 -15
- package/src/ui/components/OxyAuthChooser.tsx +722 -185
- package/src/ui/components/ProfileButton.tsx +16 -1
- package/src/ui/components/ProfileSummaryCard.tsx +2 -25
- package/src/ui/components/SurfaceScreen.tsx +48 -14
- package/src/ui/components/oxyAuthChooserStyles.ts +75 -23
- package/src/ui/components/photogrid/JustifiedPhotoGrid.tsx +158 -84
- package/src/ui/components/photogrid/__tests__/chunkPhotos.test.ts +51 -0
- package/src/ui/context/OxyContext.tsx +74 -34
- package/src/ui/hooks/queries/queryKeys.ts +15 -0
- package/src/ui/hooks/queries/useFileQueries.ts +162 -0
- package/src/ui/hooks/useAvatarPicker.ts +38 -53
- package/src/ui/hooks/useReduceMotion.ts +58 -0
- package/src/ui/hooks/useSurfaceHeader.ts +2 -1
- package/src/ui/navigation/__tests__/getSurfaceConfig.test.ts +55 -7
- package/src/ui/navigation/__tests__/surfaceNavStack.test.ts +81 -0
- package/src/ui/navigation/accountDialogManager.ts +28 -0
- package/src/ui/navigation/bottomSheetManager.ts +6 -7
- package/src/ui/navigation/routes.ts +3 -1
- package/src/ui/navigation/surfaceNavStack.ts +72 -9
- package/src/ui/navigation/surfaceRegistry.ts +91 -17
- package/src/ui/navigation/surfaces.ts +108 -29
- package/src/ui/screens/AvatarCropScreen.tsx +336 -298
- package/src/ui/screens/ChangeAvatarScreen.tsx +359 -0
- package/src/ui/screens/FileManagementScreen.tsx +189 -432
- package/src/ui/screens/WelcomeNewUserScreen.tsx +18 -48
- package/src/ui/screens/fileManagement/FileLibraryError.tsx +56 -0
- package/src/ui/screens/fileManagement/PhotoPickerSection.tsx +56 -46
- package/src/ui/screens/fileManagement/hooks/useFileUploadState.ts +55 -71
- package/src/ui/stores/resetSessionScopedStores.ts +8 -3
- package/src/ui/types/navigation.ts +2 -0
- package/src/ui/utils/avatarUtils.ts +11 -2
- package/src/ui/utils/fileManagement.ts +1 -101
- package/lib/commonjs/ui/stores/fileStore.js +0 -153
- package/lib/commonjs/ui/stores/fileStore.js.map +0 -1
- package/lib/module/ui/stores/fileStore.js +0 -145
- package/lib/module/ui/stores/fileStore.js.map +0 -1
- package/lib/typescript/commonjs/ui/stores/fileStore.d.ts +0 -31
- package/lib/typescript/commonjs/ui/stores/fileStore.d.ts.map +0 -1
- package/lib/typescript/module/ui/stores/fileStore.d.ts +0 -31
- package/lib/typescript/module/ui/stores/fileStore.d.ts.map +0 -1
- 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 {
|
|
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.
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
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 &&
|
|
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
|
-
| '
|
|
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
|
-
|
|
106
|
-
|
|
107
|
-
store.setState({
|
|
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
|
-
/**
|
|
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
|
-
*
|
|
96
|
-
*
|
|
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
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
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.
|
|
213
|
-
* responsive sheet
|
|
214
|
-
*
|
|
215
|
-
*
|
|
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
|
|
223
|
-
|
|
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 };
|