@oxyhq/services 22.11.0 → 22.12.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 (71) hide show
  1. package/lib/commonjs/ui/components/OxyAuthChooser.js +1 -1
  2. package/lib/commonjs/ui/components/OxyAuthChooser.js.map +1 -1
  3. package/lib/commonjs/ui/hooks/useSurfaceHeader.js +7 -5
  4. package/lib/commonjs/ui/hooks/useSurfaceHeader.js.map +1 -1
  5. package/lib/commonjs/ui/navigation/surfaceRegistry.js +11 -37
  6. package/lib/commonjs/ui/navigation/surfaceRegistry.js.map +1 -1
  7. package/lib/commonjs/ui/screens/AvatarCropScreen.js +9 -13
  8. package/lib/commonjs/ui/screens/AvatarCropScreen.js.map +1 -1
  9. package/lib/commonjs/ui/screens/FileManagementScreen.js +55 -13
  10. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
  11. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js +11 -0
  12. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js.map +1 -1
  13. package/lib/commonjs/ui/screens/ProfileScreen.js +91 -117
  14. package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
  15. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +22 -54
  16. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  17. package/lib/commonjs/ui/screens/fileManagement/PhotoPickerSection.js +64 -155
  18. package/lib/commonjs/ui/screens/fileManagement/PhotoPickerSection.js.map +1 -1
  19. package/lib/module/ui/components/OxyAuthChooser.js +1 -1
  20. package/lib/module/ui/components/OxyAuthChooser.js.map +1 -1
  21. package/lib/module/ui/hooks/useSurfaceHeader.js +7 -5
  22. package/lib/module/ui/hooks/useSurfaceHeader.js.map +1 -1
  23. package/lib/module/ui/navigation/surfaceRegistry.js +11 -37
  24. package/lib/module/ui/navigation/surfaceRegistry.js.map +1 -1
  25. package/lib/module/ui/screens/AvatarCropScreen.js +9 -13
  26. package/lib/module/ui/screens/AvatarCropScreen.js.map +1 -1
  27. package/lib/module/ui/screens/FileManagementScreen.js +55 -13
  28. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
  29. package/lib/module/ui/screens/PaymentGatewayScreen.js +11 -0
  30. package/lib/module/ui/screens/PaymentGatewayScreen.js.map +1 -1
  31. package/lib/module/ui/screens/ProfileScreen.js +93 -119
  32. package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
  33. package/lib/module/ui/screens/WelcomeNewUserScreen.js +23 -54
  34. package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  35. package/lib/module/ui/screens/fileManagement/PhotoPickerSection.js +64 -155
  36. package/lib/module/ui/screens/fileManagement/PhotoPickerSection.js.map +1 -1
  37. package/lib/typescript/commonjs/ui/hooks/useSurfaceHeader.d.ts +7 -5
  38. package/lib/typescript/commonjs/ui/hooks/useSurfaceHeader.d.ts.map +1 -1
  39. package/lib/typescript/commonjs/ui/navigation/surfaceRegistry.d.ts +8 -9
  40. package/lib/typescript/commonjs/ui/navigation/surfaceRegistry.d.ts.map +1 -1
  41. package/lib/typescript/commonjs/ui/screens/AvatarCropScreen.d.ts.map +1 -1
  42. package/lib/typescript/commonjs/ui/screens/FileManagementScreen.d.ts.map +1 -1
  43. package/lib/typescript/commonjs/ui/screens/PaymentGatewayScreen.d.ts.map +1 -1
  44. package/lib/typescript/commonjs/ui/screens/ProfileScreen.d.ts.map +1 -1
  45. package/lib/typescript/commonjs/ui/screens/WelcomeNewUserScreen.d.ts +2 -1
  46. package/lib/typescript/commonjs/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
  47. package/lib/typescript/commonjs/ui/screens/fileManagement/PhotoPickerSection.d.ts +0 -6
  48. package/lib/typescript/commonjs/ui/screens/fileManagement/PhotoPickerSection.d.ts.map +1 -1
  49. package/lib/typescript/module/ui/hooks/useSurfaceHeader.d.ts +7 -5
  50. package/lib/typescript/module/ui/hooks/useSurfaceHeader.d.ts.map +1 -1
  51. package/lib/typescript/module/ui/navigation/surfaceRegistry.d.ts +8 -9
  52. package/lib/typescript/module/ui/navigation/surfaceRegistry.d.ts.map +1 -1
  53. package/lib/typescript/module/ui/screens/AvatarCropScreen.d.ts.map +1 -1
  54. package/lib/typescript/module/ui/screens/FileManagementScreen.d.ts.map +1 -1
  55. package/lib/typescript/module/ui/screens/PaymentGatewayScreen.d.ts.map +1 -1
  56. package/lib/typescript/module/ui/screens/ProfileScreen.d.ts.map +1 -1
  57. package/lib/typescript/module/ui/screens/WelcomeNewUserScreen.d.ts +2 -1
  58. package/lib/typescript/module/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
  59. package/lib/typescript/module/ui/screens/fileManagement/PhotoPickerSection.d.ts +0 -6
  60. package/lib/typescript/module/ui/screens/fileManagement/PhotoPickerSection.d.ts.map +1 -1
  61. package/package.json +6 -6
  62. package/src/ui/components/OxyAuthChooser.tsx +1 -1
  63. package/src/ui/hooks/useSurfaceHeader.ts +25 -5
  64. package/src/ui/navigation/__tests__/getSurfaceConfig.test.ts +16 -2
  65. package/src/ui/navigation/surfaceRegistry.ts +14 -42
  66. package/src/ui/screens/AvatarCropScreen.tsx +14 -23
  67. package/src/ui/screens/FileManagementScreen.tsx +69 -25
  68. package/src/ui/screens/PaymentGatewayScreen.tsx +11 -0
  69. package/src/ui/screens/ProfileScreen.tsx +96 -111
  70. package/src/ui/screens/WelcomeNewUserScreen.tsx +23 -63
  71. package/src/ui/screens/fileManagement/PhotoPickerSection.tsx +68 -172
@@ -167,10 +167,9 @@ export interface SurfaceRouteConfig {
167
167
  /**
168
168
  * Whether the surface renders the Dialog's OWN navigation header (sticky
169
169
  * gradient nav bar + large collapsing title over the surface's scroll content).
170
- * `true` for every route screen screens render NO header of their own and
171
- * declare their title/subtitle (+ any action slot) via `useSurfaceHeader`.
172
- * `false` for surfaces with their own chrome (the account dialog, the flagship
173
- * full-bleed image picker).
170
+ * `true` for EVERY route — the whole SDK UI is unified on the shared header:
171
+ * screens render NO header of their own and declare their title/subtitle (+ any
172
+ * action slot / `onBack`) via `useSurfaceHeader`. No route opts out anymore.
174
173
  */
175
174
  header: boolean;
176
175
  /** Body-pan activation strategy — reserved (owned by Bloom's Dialog surface). */
@@ -182,11 +181,11 @@ export interface SurfaceRouteConfig {
182
181
  }
183
182
  /**
184
183
  * Resolve the surface configuration for a route + props. Every route defaults to
185
- * the responsive sheet and MORPHS in place when navigated to from within a surface
186
- * (no route stacks — genuine overlays are Bloom-raw `surfaces.present`/`confirm`
187
- * calls, outside this registry). The image-only FileManagement picker is a normal
188
- * sheet that owns its own scroll + translucent bar (no Dialog nav header); every
189
- * other own-scroller is marked `scrollable: false`.
184
+ * the responsive sheet, renders the SHARED Dialog nav header, and MORPHS in place
185
+ * when navigated to from within a surface (no route stacks — genuine overlays are
186
+ * Bloom-raw `surfaces.present`/`confirm` calls, outside this registry). The
187
+ * image-only FileManagement picker is a normal sheet that owns its own scroll and
188
+ * grows to a large morph target; every other own-scroller is `scrollable: false`.
190
189
  */
191
190
  export declare const getSurfaceConfig: (route: RouteName, props: Record<string, unknown>) => SurfaceRouteConfig;
192
191
  /** Convenience: just the presentation taxonomy for a route + props. */
@@ -1 +1 @@
1
- {"version":3,"file":"surfaceRegistry.d.ts","sourceRoot":"","sources":["../../../../../src/ui/navigation/surfaceRegistry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"surfaceRegistry.d.ts","sourceRoot":"","sources":["../../../../../src/ui/navigation/surfaceRegistry.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"AvatarCropScreen.d.ts","sourceRoot":"","sources":["../../../../../src/ui/screens/AvatarCropScreen.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AA+B/B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAqB,CAAC;AAK3D,mDAAmD;AACnD,MAAM,WAAW,gBAAgB;IAC7B,oDAAoD;IACpD,GAAG,EAAE,MAAM,CAAC;IACZ,iCAAiC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,IAAI,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,qBAAsB,SAAQ,eAAe;IAC1D,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAuPD,QAAA,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAs0BrD,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"AvatarCropScreen.d.ts","sourceRoot":"","sources":["../../../../../src/ui/screens/AvatarCropScreen.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AA8B/B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAqB,CAAC;AAK3D,mDAAmD;AACnD,MAAM,WAAW,gBAAgB;IAC7B,oDAAoD;IACpD,GAAG,EAAE,MAAM,CAAC;IACZ,iCAAiC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,IAAI,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,qBAAsB,SAAQ,eAAe;IAC1D,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAuPD,QAAA,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CA8zBrD,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"FileManagementScreen.d.ts","sourceRoot":"","sources":["../../../../../src/ui/screens/FileManagementScreen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiD,MAAM,OAAO,CAAC;AActE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,4BAAyB,CAAC;AAiEzE,QAAA,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CA8vC7D,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"FileManagementScreen.d.ts","sourceRoot":"","sources":["../../../../../src/ui/screens/FileManagementScreen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiD,MAAM,OAAO,CAAC;AActE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,4BAAyB,CAAC;AAiEzE,QAAA,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CA0yC7D,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"PaymentGatewayScreen.d.ts","sourceRoot":"","sources":["../../../../../src/ui/screens/PaymentGatewayScreen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAQ/B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAqB,CAAC;AAc3D,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAe,MAAM,gCAA6B,CAAC;AAElG,YAAY,EAAE,WAAW,EAAE,oBAAoB,EAAE,CAAC;AAElD,UAAU,yBAA0B,SAAQ,eAAe;IACvD,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACzD,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAOD,QAAA,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CAmP7D,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"PaymentGatewayScreen.d.ts","sourceRoot":"","sources":["../../../../../src/ui/screens/PaymentGatewayScreen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAQ/B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAqB,CAAC;AAe3D,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAe,MAAM,gCAA6B,CAAC;AAElG,YAAY,EAAE,WAAW,EAAE,oBAAoB,EAAE,CAAC;AAElD,UAAU,yBAA0B,SAAQ,eAAe;IACvD,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACzD,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAOD,QAAA,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CA6P7D,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ProfileScreen.d.ts","sourceRoot":"","sources":["../../../../../src/ui/screens/ProfileScreen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAqB,CAAC;AAe3D,UAAU,kBAAmB,SAAQ,eAAe;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAOD,QAAA,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA+S/C,CAAC;AAwCF,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"ProfileScreen.d.ts","sourceRoot":"","sources":["../../../../../src/ui/screens/ProfileScreen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAqB,CAAC;AAe3D,UAAU,kBAAmB,SAAQ,eAAe;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAOD,QAAA,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAgS/C,CAAC;AAuCF,eAAe,aAAa,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import type React from 'react';
2
2
  import type { BaseScreenProps } from '../types/navigation.js';
3
+ import { type User } from '@oxyhq/core';
3
4
  /**
4
5
  * Post-signup welcome & onboarding screen.
5
6
  * - Greets the newly registered user
@@ -7,7 +8,7 @@ import type { BaseScreenProps } from '../types/navigation.js';
7
8
  * - Only when the user presses "Continue" do we invoke onAuthenticated to finish flow & close sheet
8
9
  */
9
10
  declare const WelcomeNewUserScreen: React.FC<BaseScreenProps & {
10
- newUser?: any;
11
+ newUser?: User;
11
12
  }>;
12
13
  export default WelcomeNewUserScreen;
13
14
  //# sourceMappingURL=WelcomeNewUserScreen.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"WelcomeNewUserScreen.d.ts","sourceRoot":"","sources":["../../../../../src/ui/screens/WelcomeNewUserScreen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAqB,CAAC;AAiD3D;;;;;GAKG;AACH,QAAA,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,GAAG;IAAE,OAAO,CAAC,EAAE,GAAG,CAAA;CAAE,CAsRvE,CAAC;AAkFF,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"WelcomeNewUserScreen.d.ts","sourceRoot":"","sources":["../../../../../src/ui/screens/WelcomeNewUserScreen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAqB,CAAC;AAY3D,OAAO,EAAyB,KAAK,IAAI,EAAE,MAAM,aAAa,CAAC;AAK/D;;;;;GAKG;AACH,QAAA,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,GAAG;IAAE,OAAO,CAAC,EAAE,IAAI,CAAA;CAAE,CA6RxE,CAAC;AAoEF,eAAe,oBAAoB,CAAC"}
@@ -14,10 +14,6 @@ export interface PhotoPickerViewProps {
14
14
  refreshing: boolean;
15
15
  uploading: boolean;
16
16
  isPickingDocument: boolean;
17
- uploadProgress: {
18
- current: number;
19
- total: number;
20
- } | null;
21
17
  hasMore: boolean;
22
18
  loadingMore: boolean;
23
19
  /**
@@ -40,8 +36,6 @@ export interface PhotoPickerViewProps {
40
36
  onUpload: () => void;
41
37
  onRefresh: () => void;
42
38
  onLoadMore: () => void;
43
- onCancel: () => void;
44
- onConfirm: () => void;
45
39
  t: (key: string, vars?: Record<string, string | number>) => string;
46
40
  }
47
41
  declare const PhotoPickerView: React.FC<PhotoPickerViewProps>;
@@ -1 +1 @@
1
- {"version":3,"file":"PhotoPickerSection.d.ts","sourceRoot":"","sources":["../../../../../../src/ui/screens/fileManagement/PhotoPickerSection.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAgBtE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA4FhD;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACjC,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,cAAc,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC1D,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;IACrB;;;;;OAKG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB,+EAA+E;IAC/E,SAAS,EAAE,OAAO,CAAC;IACnB,iEAAiE;IACjE,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,MAAM,GAAG,SAAS,CAAC;IACxD,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IAC7C,cAAc,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IAC9C,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,KAAK,MAAM,CAAC;CACtE;AA4LD,QAAA,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAwZnD,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"PhotoPickerSection.d.ts","sourceRoot":"","sources":["../../../../../../src/ui/screens/fileManagement/PhotoPickerSection.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAgBtE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAiFhD;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACjC,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;IACrB;;;;;OAKG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB,+EAA+E;IAC/E,SAAS,EAAE,OAAO,CAAC;IACnB,iEAAiE;IACjE,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,MAAM,GAAG,SAAS,CAAC;IACxD,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IAC7C,cAAc,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IAC9C,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,KAAK,MAAM,CAAC;CACtE;AA+MD,QAAA,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA2SnD,CAAC;AAEF,eAAe,eAAe,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxyhq/services",
3
- "version": "22.11.0",
3
+ "version": "22.12.0",
4
4
  "description": "OxyHQ Expo/React Native SDK — UI components, screens, and native features",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
@@ -109,7 +109,7 @@
109
109
  "delete-debug-view": "rm -rf ./lib/commonjs/components/bottomSheetDebugView ./lib/module/components/bottomSheetDebugView ./lib/typescript/components/bottomSheetDebugView || true",
110
110
  "delete-dts.js": "find ./lib/commonjs -name '*.d.js*' -delete && find ./lib/module -name '*.d.js*' -delete",
111
111
  "release": "rm -rf lib && bun run build && release-it",
112
- "prepublishOnly": "bun run typescript && bun run test && bun run build"
112
+ "prepublishOnly": "node ../../scripts/assert-bun-publish.mjs && bun run typescript && bun run test && bun run build"
113
113
  },
114
114
  "release-it": {
115
115
  "git": {
@@ -127,7 +127,7 @@
127
127
  },
128
128
  "dependencies": {
129
129
  "@oxyhq/contracts": "0.17.0",
130
- "@oxyhq/core": "^12.10.1",
130
+ "@oxyhq/core": "^12.10.3",
131
131
  "@simplewebauthn/browser": "^13.3.0",
132
132
  "color": "^4.2.3"
133
133
  },
@@ -136,7 +136,7 @@
136
136
  "@commitlint/cli": "^17.6.5",
137
137
  "@commitlint/config-conventional": "^17.6.5",
138
138
  "@expo/vector-icons": "^15.0.3",
139
- "@oxyhq/core": "12.10.2",
139
+ "@oxyhq/core": "12.10.3",
140
140
  "@react-native-async-storage/async-storage": "^2.0.0",
141
141
  "@react-native-community/netinfo": "^11.4.1",
142
142
  "@react-native/babel-preset": "^0.86.0",
@@ -176,8 +176,8 @@
176
176
  },
177
177
  "peerDependencies": {
178
178
  "@expo/vector-icons": "^15.0.3",
179
- "@oxyhq/bloom": ">=0.48.0",
180
- "@oxyhq/core": "^12.9.0",
179
+ "@oxyhq/bloom": "^0.49.1",
180
+ "@oxyhq/core": "^12.10.0",
181
181
  "@react-native-async-storage/async-storage": "^2.0.0",
182
182
  "@react-native-community/netinfo": "^11.4.1",
183
183
  "@tanstack/query-async-storage-persister": "^5.101",
@@ -396,7 +396,7 @@ const OxyAuthChooser: React.FC<OxyAuthChooserProps> = ({ onComplete }) => {
396
396
  onOpenSettings: () => openUrl(ACCOUNTS_APP_URL),
397
397
  onOpenData: () => openUrl(`${ACCOUNTS_APP_URL}/data`),
398
398
  onManageStorage: () => openUrl(`${ACCOUNTS_APP_URL}/storage`),
399
- onUpgradeStorage: () => openUrl(`${ACCOUNTS_APP_URL}/storage`),
399
+ onUpgradeStorage: () => openUrl(`${ACCOUNTS_APP_URL}/payments`),
400
400
  onHelp: () => openSheet('HelpSupport'),
401
401
  onPrivacy: () => openSheet({ screen: 'LegalDocuments', props: { initialStep: 1 } }),
402
402
  onTerms: () => openSheet({ screen: 'LegalDocuments', props: { initialStep: 2 } }),
@@ -6,14 +6,28 @@ import type { DialogHeaderConfig } from '@oxyhq/bloom/dialog';
6
6
  * (translated) title/subtitle and optional slot nodes. Back/close affordances
7
7
  * are owned by the surface host (`SurfaceScreen`) — a screen never wires them.
8
8
  *
9
- * A `right` slot is the canonical place for a screen-state action (e.g. a Save
10
- * button whose disabled/loading state reflects the form). Slot nodes MUST be
11
- * referentially stable (memoize them with `useMemo`) so the header does not
12
- * thrash.
9
+ * Alongside the classic slots (`left`/`right`) a screen can declare the rich
10
+ * design-system fields Bloom's nav header supports: the single trailing
11
+ * `primaryAction` CTA (Upload / Save), a trailing icon `actions` row, a header
12
+ * `search` / `segments` in the large-title zone, an `onImage` `tone` over media,
13
+ * and a wizard `progress` bar. Object/slot fields MUST be referentially stable
14
+ * (memoize them with `useMemo`) so the header does not thrash.
13
15
  */
14
16
  export type SurfaceHeaderContent = Pick<
15
17
  DialogHeaderConfig,
16
- 'title' | 'titleContent' | 'subtitle' | 'largeTitle' | 'left' | 'right' | 'onBack'
18
+ | 'title'
19
+ | 'titleContent'
20
+ | 'subtitle'
21
+ | 'largeTitle'
22
+ | 'left'
23
+ | 'right'
24
+ | 'onBack'
25
+ | 'primaryAction'
26
+ | 'actions'
27
+ | 'search'
28
+ | 'segments'
29
+ | 'tone'
30
+ | 'progress'
17
31
  >;
18
32
 
19
33
  interface SurfaceHeaderContextValue {
@@ -53,5 +67,11 @@ export function useSurfaceHeader(content: SurfaceHeaderContent | null | undefine
53
67
  content?.left,
54
68
  content?.right,
55
69
  content?.onBack,
70
+ content?.primaryAction,
71
+ content?.actions,
72
+ content?.search,
73
+ content?.segments,
74
+ content?.tone,
75
+ content?.progress,
56
76
  ]);
57
77
  }
@@ -24,9 +24,12 @@ describe('getSurfaceConfig presentation', () => {
24
24
  expect(config.presentation).toBe('sheet');
25
25
  expect(config.stacks).toBe(false);
26
26
  // PhotoPickerView owns its own FlatList → the host must not wrap it in a
27
- // ScrollView; and its own translucent bar → no Dialog nav header.
27
+ // ScrollView. It now renders the SHARED Dialog nav header (Cancel / title /
28
+ // Upload) like every other screen — its bespoke bar is gone.
28
29
  expect(config.scrollable).toBe(false);
29
- expect(config.header).toBe(false);
30
+ expect(config.header).toBe(true);
31
+ // …and it grows to the large morph target so the grid has room.
32
+ expect(config.frameSize).toEqual({ heightRatio: 0.9, maxWidth: 640 });
30
33
  });
31
34
 
32
35
  it('morphs the surface for every route, the picker included', () => {
@@ -73,6 +76,17 @@ describe('getSurfaceConfig presentation', () => {
73
76
  expect(getSurfaceConfig('AvatarCrop', {}).header).toBe(true);
74
77
  });
75
78
 
79
+ it('renders the shared nav header on every route — nothing is headerless', () => {
80
+ // The whole SDK UI is unified on the Dialog nav header. The last four
81
+ // holdouts (Profile / PaymentGateway / WelcomeNewUser + the image picker)
82
+ // now declare their chrome through `useSurfaceHeader` like every screen.
83
+ expect(getSurfaceConfig('Profile', {}).header).toBe(true);
84
+ expect(getSurfaceConfig('PaymentGateway', {}).header).toBe(true);
85
+ expect(getSurfaceConfig('WelcomeNewUser', {}).header).toBe(true);
86
+ expect(getSurfaceConfig('ManageAccount', {}).header).toBe(true);
87
+ expect(getSurfaceConfig('FileManagement', imageOnlyPickerProps).header).toBe(true);
88
+ });
89
+
76
90
  it('keeps FileManagement on the sheet when it is not an image-only picker', () => {
77
91
  // Browse mode (no selectMode) — the standard file manager.
78
92
  expect(getSurfaceConfig('FileManagement', {}).presentation).toBe('sheet');
@@ -181,10 +181,9 @@ export interface SurfaceRouteConfig {
181
181
  /**
182
182
  * Whether the surface renders the Dialog's OWN navigation header (sticky
183
183
  * gradient nav bar + large collapsing title over the surface's scroll content).
184
- * `true` for every route screen screens render NO header of their own and
185
- * declare their title/subtitle (+ any action slot) via `useSurfaceHeader`.
186
- * `false` for surfaces with their own chrome (the account dialog, the flagship
187
- * full-bleed image picker).
184
+ * `true` for EVERY route — the whole SDK UI is unified on the shared header:
185
+ * screens render NO header of their own and declare their title/subtitle (+ any
186
+ * action slot / `onBack`) via `useSurfaceHeader`. No route opts out anymore.
188
187
  */
189
188
  header: boolean;
190
189
  /** Body-pan activation strategy — reserved (owned by Bloom's Dialog surface). */
@@ -206,30 +205,6 @@ const DEFAULT_SURFACE_CONFIG: SurfaceRouteConfig = {
206
205
  dynamicBackdrop: true,
207
206
  };
208
207
 
209
- /**
210
- * Routes that render NO Dialog nav header — they own their chrome:
211
- * - `PaymentGateway` — the payment surface owns its controls.
212
- * - `WelcomeNewUser` — a full-bleed onboarding wizard with its own step chrome.
213
- * - `Profile` — a full profile view, no nav-header chrome.
214
- * (The flagship full-bleed image picker is handled separately below.)
215
- *
216
- * `AccountDialog` used to be here — it now uses the SHARED Dialog nav header like
217
- * every other screen (its per-view title/subtitle + view-back go through
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.
226
- */
227
- const HEADERLESS_ROUTES: ReadonlySet<RouteName> = new Set<RouteName>([
228
- 'PaymentGateway',
229
- 'WelcomeNewUser',
230
- 'Profile',
231
- ]);
232
-
233
208
  /**
234
209
  * Predicate matching `FileManagementScreen`'s internal `isImageOnlyPicker`
235
210
  * derivation. When the consumer restricts to image MIME types (no videos, no
@@ -272,11 +247,11 @@ const OWN_SCROLL_CONTAINER_ROUTES: ReadonlySet<RouteName> = new Set<RouteName>([
272
247
 
273
248
  /**
274
249
  * 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`.
250
+ * the responsive sheet, renders the SHARED Dialog nav header, and MORPHS in place
251
+ * when navigated to from within a surface (no route stacks — genuine overlays are
252
+ * Bloom-raw `surfaces.present`/`confirm` calls, outside this registry). The
253
+ * image-only FileManagement picker is a normal sheet that owns its own scroll and
254
+ * grows to a large morph target; every other own-scroller is `scrollable: false`.
280
255
  */
281
256
  export const getSurfaceConfig = (
282
257
  route: RouteName,
@@ -284,21 +259,18 @@ export const getSurfaceConfig = (
284
259
  ): SurfaceRouteConfig => {
285
260
  if (route === 'FileManagement' && isFileManagementImageOnlyPicker(props)) {
286
261
  // 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.
262
+ // own-scroller (`PhotoPickerView`'s FlatList) that paints its full-bleed black
263
+ // photo canvas as CONTENT under the SHARED Dialog nav header (Cancel / title /
264
+ // Upload), exactly like the crop stage under the same bar. It needs ROOM for
265
+ // the photo grid, so it declares an explicit LARGE morph target — the panel
266
+ // grows UP to a near-full-height, wider card on entry (and back down on
267
+ // pick→crop), the grid scrolling within.
292
268
  return {
293
269
  ...DEFAULT_SURFACE_CONFIG,
294
270
  scrollable: false,
295
- header: false,
296
271
  frameSize: { heightRatio: 0.9, maxWidth: 640 },
297
272
  };
298
273
  }
299
- if (HEADERLESS_ROUTES.has(route)) {
300
- return { ...DEFAULT_SURFACE_CONFIG, header: false };
301
- }
302
274
  if (OWN_SCROLL_CONTAINER_ROUTES.has(route)) {
303
275
  // Own-scroller list screens keep the nav header (static, non-collapsing —
304
276
  // there is no Dialog scroll offset to drive the large-title collapse).
@@ -50,12 +50,11 @@ import Animated, {
50
50
  } from 'react-native-reanimated';
51
51
  import { useQuery, keepPreviousData } from '@tanstack/react-query';
52
52
  import { useTheme } from '@oxyhq/bloom/theme';
53
- import { Button } from '@oxyhq/bloom/button';
54
53
  import { logger } from '@oxyhq/core';
55
54
  import { useOxy } from '../context/OxyContext';
56
55
  import { useI18n } from '../hooks/useI18n';
57
56
  import { useReduceMotion } from '../hooks/useReduceMotion';
58
- import { useSurfaceHeader } from '../hooks/useSurfaceHeader';
57
+ import { useSurfaceHeader, type SurfaceHeaderContent } from '../hooks/useSurfaceHeader';
59
58
  import { toast } from '@oxyhq/bloom';
60
59
  import type { BaseScreenProps } from '../types/navigation';
61
60
 
@@ -863,27 +862,19 @@ const AvatarCropScreen: React.FC<AvatarCropScreenProps> = ({
863
862
  }, [baseFit, effectiveUri, naturalSize, dismiss, t]);
864
863
 
865
864
  /**
866
- * The surface's primary action, mounted into the Dialog nav bar's right slot
867
- * (which is why it must stay referentially stable). While processing it keeps
868
- * its width and shows a spinner; the a11y label carries the "Saving…" state
869
- * the visible label can no longer show.
865
+ * The surface's "Use photo" CTA, declared through the Dialog header's
866
+ * `primaryAction` (a real Bloom Button with a loading spinner + disabled
867
+ * state) the standardized trailing action, no bespoke node. Memoized so the
868
+ * header does not thrash.
870
869
  */
871
- const doneAction = useMemo(
872
- () => (
873
- <Button
874
- variant="primary"
875
- size="small"
876
- onPress={() => void handleConfirm()}
877
- disabled={isProcessing || !baseFit}
878
- loading={isProcessing}
879
- accessibilityLabel={
880
- isProcessing ? t('editProfile.crop.saving') : t('editProfile.crop.confirm')
881
- }
882
- >
883
- {t('editProfile.crop.confirm')}
884
- </Button>
885
- ),
886
- [baseFit, handleConfirm, isProcessing, t],
870
+ const donePrimaryAction = useMemo<SurfaceHeaderContent['primaryAction']>(
871
+ () => ({
872
+ label: t('editProfile.crop.confirm'),
873
+ onPress: () => void handleConfirm(),
874
+ disabled: isProcessing || !baseFit,
875
+ loading: isProcessing,
876
+ }),
877
+ [t, handleConfirm, isProcessing, baseFit],
887
878
  );
888
879
 
889
880
  // No bar of our own: the surface owns the chrome. `goBack` pops back to the
@@ -892,7 +883,7 @@ const AvatarCropScreen: React.FC<AvatarCropScreenProps> = ({
892
883
  useSurfaceHeader({
893
884
  title: t('editProfile.crop.title'),
894
885
  largeTitle: false,
895
- right: doneAction,
886
+ primaryAction: donePrimaryAction,
896
887
  onBack: goBack,
897
888
  });
898
889
 
@@ -21,7 +21,7 @@ import { Pressable } from 'react-native';
21
21
  import type { FileMetadata } from '@oxyhq/core';
22
22
  import { queryKeys } from '../hooks/queries/queryKeys';
23
23
  import { useUserFilesInfinite, removeFileFromCache, patchFileMetadataInCache } from '../hooks/queries/useFileQueries';
24
- import { useSurfaceHeader } from '../hooks/useSurfaceHeader';
24
+ import { useSurfaceHeader, type SurfaceHeaderContent } from '../hooks/useSurfaceHeader';
25
25
  import { SurfaceHeaderAction } from '../components/SurfaceHeaderAction';
26
26
  import JustifiedPhotoGrid from '../components/photogrid/JustifiedPhotoGrid';
27
27
  import { useTheme } from '@oxyhq/bloom/theme';
@@ -990,6 +990,51 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
990
990
  </Pressable>
991
991
  ), [handleCancelUpload, colors.text, t]);
992
992
 
993
+ // --- Image-only picker: shared-header chrome -----------------------------
994
+ // The flagship photo picker now rides the SAME Dialog nav header as every
995
+ // screen (Cancel / "Choose Photo" / Upload) instead of painting its own bar.
996
+ // Ownership + upload permission gate the Upload action, mirroring the picker's
997
+ // empty-state upload button.
998
+ const isOwner = user?.id === targetUserId;
999
+ const allowUpload = isOwner && allowUploadInSelectMode;
1000
+
1001
+ // Cancel = the nav bar's back affordance. Legacy callback callers keep their
1002
+ // close/back behaviour; the promise-based avatar picker dismisses its surface.
1003
+ const pickerCancel = useCallback(() => {
1004
+ if (onSelect || onConfirmSelection) {
1005
+ if (onClose) onClose();
1006
+ else goBack?.();
1007
+ } else {
1008
+ dismiss?.();
1009
+ }
1010
+ }, [onSelect, onConfirmSelection, onClose, goBack, dismiss]);
1011
+
1012
+ // The picker's ONE trailing CTA, declared through the Dialog header's
1013
+ // `primaryAction` (a proper Bloom Button with loading/disabled) — the
1014
+ // multi-select confirm ("Done (N)") or, single-select, the Upload action whose
1015
+ // loading state reflects an in-flight device upload. Memoized so the header
1016
+ // does not thrash.
1017
+ const pickerPrimaryAction = useMemo<SurfaceHeaderContent['primaryAction']>(() => {
1018
+ if (multiSelect) {
1019
+ return {
1020
+ label: t('fileManagement.doneWithCount', { count: selectedIds.size }),
1021
+ onPress: confirmMultiSelection,
1022
+ disabled: selectedIds.size === 0,
1023
+ };
1024
+ }
1025
+ if (isOwner && allowUpload) {
1026
+ return {
1027
+ label: t('fileManagement.upload'),
1028
+ onPress: handleFileUpload,
1029
+ loading: uploading || isPickingDocument,
1030
+ };
1031
+ }
1032
+ return undefined;
1033
+ }, [
1034
+ multiSelect, selectedIds.size, confirmMultiSelection, isOwner, allowUpload,
1035
+ t, handleFileUpload, uploading, isPickingDocument,
1036
+ ]);
1037
+
993
1038
  useSurfaceHeader(
994
1039
  showUploadPreview
995
1040
  ? {
@@ -998,16 +1043,26 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
998
1043
  left: fmHeaderBack,
999
1044
  largeTitle: false,
1000
1045
  }
1001
- : {
1002
- title: selectMode
1003
- ? (multiSelect ? (maxSelection ? t('fileManagement.selectedWithMax', { count: selectedIds.size, max: maxSelection }) : t('fileManagement.selected', { count: selectedIds.size })) : t('fileManagement.selectFile'))
1004
- : (viewMode === 'photos' ? t('fileManagement.photos') : t('fileManagement.title')),
1005
- subtitle: selectMode
1006
- ? (multiSelect ? t('fileManagement.available', { count: filteredFiles.length }) : t('fileManagement.tapToSelect'))
1007
- : (filteredFiles.length === 1 ? t('fileManagement.itemCount', { count: filteredFiles.length }) : t('fileManagement.itemCount_plural', { count: filteredFiles.length })),
1008
- right: fmHeaderRight,
1009
- largeTitle: false,
1010
- },
1046
+ : isImageOnlyPicker
1047
+ ? {
1048
+ // ONE shared header Cancel (back) / "Choose Photo" / Upload in
1049
+ // `onImage` tone so the chrome stays legible over the black grid.
1050
+ title: t('fileManagement.choosePhoto'),
1051
+ largeTitle: false,
1052
+ onBack: pickerCancel,
1053
+ primaryAction: pickerPrimaryAction,
1054
+ tone: 'onImage',
1055
+ }
1056
+ : {
1057
+ title: selectMode
1058
+ ? (multiSelect ? (maxSelection ? t('fileManagement.selectedWithMax', { count: selectedIds.size, max: maxSelection }) : t('fileManagement.selected', { count: selectedIds.size })) : t('fileManagement.selectFile'))
1059
+ : (viewMode === 'photos' ? t('fileManagement.photos') : t('fileManagement.title')),
1060
+ subtitle: selectMode
1061
+ ? (multiSelect ? t('fileManagement.available', { count: filteredFiles.length }) : t('fileManagement.tapToSelect'))
1062
+ : (filteredFiles.length === 1 ? t('fileManagement.itemCount', { count: filteredFiles.length }) : t('fileManagement.itemCount_plural', { count: filteredFiles.length })),
1063
+ right: fmHeaderRight,
1064
+ largeTitle: false,
1065
+ },
1011
1066
  );
1012
1067
 
1013
1068
  if (isLoadingFiles && !isImageOnlyPicker) {
@@ -1067,9 +1122,10 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1067
1122
  const photosOnly = filteredFiles.filter(
1068
1123
  (file) => file.contentType.startsWith('image/'),
1069
1124
  );
1070
- const isOwner = user?.id === targetUserId;
1071
- const allowUpload = isOwner && allowUploadInSelectMode;
1072
1125
 
1126
+ // Chrome (Cancel / "Choose Photo" / Upload) lives on the shared Dialog nav
1127
+ // header (see the `useSurfaceHeader` call above); the picker owns only the
1128
+ // full-bleed photo grid as content.
1073
1129
  return (
1074
1130
  <PhotoPickerView
1075
1131
  photos={photosOnly}
@@ -1080,7 +1136,6 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1080
1136
  refreshing={isRefreshingFiles}
1081
1137
  uploading={uploading}
1082
1138
  isPickingDocument={isPickingDocument}
1083
- uploadProgress={uploadProgress}
1084
1139
  hasMore={hasMoreFiles}
1085
1140
  loadingMore={isFetchingMore}
1086
1141
  loading={isLoadingFiles}
@@ -1096,17 +1151,6 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1096
1151
  onUpload={handleFileUpload}
1097
1152
  onRefresh={() => filesQuery.refetch()}
1098
1153
  onLoadMore={() => filesQuery.fetchNextPage()}
1099
- onCancel={() => {
1100
- if (onSelect || onConfirmSelection) {
1101
- // Legacy callback caller: preserve close/back behaviour.
1102
- if (onClose) onClose();
1103
- else goBack?.();
1104
- } else {
1105
- // Promise picker (avatar): dismiss just this surface.
1106
- dismiss?.();
1107
- }
1108
- }}
1109
- onConfirm={confirmMultiSelection}
1110
1154
  t={t}
1111
1155
  />
1112
1156
  );
@@ -12,6 +12,7 @@ import { useTheme } from '@oxyhq/bloom/theme';
12
12
  import { H4 } from '@oxyhq/bloom/typography';
13
13
  import { Ionicons } from '@expo/vector-icons';
14
14
  import { useI18n } from '../hooks/useI18n';
15
+ import { useSurfaceHeader } from '../hooks/useSurfaceHeader';
15
16
  import QRCode from 'react-native-qrcode-svg';
16
17
 
17
18
  import PaymentSummaryStep from '../components/payment/PaymentSummaryStep';
@@ -175,6 +176,16 @@ const PaymentGatewayScreen: React.FC<PaymentGatewayScreenProps> = (props) => {
175
176
  }
176
177
  }, [onPaymentResult, onClose, goBack]);
177
178
 
179
+ // Shared Dialog nav header: a stable "Payment" title + a back affordance that
180
+ // steps the wizard back once past the first step (the step components keep
181
+ // their own bottom Back/Continue CTAs; the header's close dismisses, matching
182
+ // the pre-existing backdrop-dismiss).
183
+ useSurfaceHeader({
184
+ title: t('payment.title'),
185
+ largeTitle: false,
186
+ onBack: currentStep > 0 ? prevStep : undefined,
187
+ });
188
+
178
189
  // Validate amount
179
190
  if (!amount || Number.isNaN(Number(amount)) || Number(amount) <= 0) {
180
191
  return (