@oxyhq/bloom 0.59.0 → 0.61.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 (54) hide show
  1. package/lib/commonjs/context-menu/index.web.js +2 -1
  2. package/lib/commonjs/context-menu/index.web.js.map +1 -1
  3. package/lib/commonjs/image-aspect-ratio-cache/imageAspectRatioCache.js +18 -1
  4. package/lib/commonjs/image-aspect-ratio-cache/imageAspectRatioCache.js.map +1 -1
  5. package/lib/commonjs/image-aspect-ratio-cache/index.js +6 -0
  6. package/lib/commonjs/image-aspect-ratio-cache/index.js.map +1 -1
  7. package/lib/commonjs/overlay/index.js +2 -2
  8. package/lib/commonjs/popover/index.web.js +2 -1
  9. package/lib/commonjs/popover/index.web.js.map +1 -1
  10. package/lib/commonjs/select/index.web.js +2 -1
  11. package/lib/commonjs/select/index.web.js.map +1 -1
  12. package/lib/commonjs/zoomable-image-gallery/ZoomableImageGallery.js +15 -6
  13. package/lib/commonjs/zoomable-image-gallery/ZoomableImageGallery.js.map +1 -1
  14. package/lib/module/context-menu/index.web.js +2 -1
  15. package/lib/module/context-menu/index.web.js.map +1 -1
  16. package/lib/module/image-aspect-ratio-cache/imageAspectRatioCache.js +16 -0
  17. package/lib/module/image-aspect-ratio-cache/imageAspectRatioCache.js.map +1 -1
  18. package/lib/module/image-aspect-ratio-cache/index.js +1 -1
  19. package/lib/module/image-aspect-ratio-cache/index.js.map +1 -1
  20. package/lib/module/overlay/index.js +2 -2
  21. package/lib/module/popover/index.web.js +3 -2
  22. package/lib/module/popover/index.web.js.map +1 -1
  23. package/lib/module/select/index.web.js +2 -1
  24. package/lib/module/select/index.web.js.map +1 -1
  25. package/lib/module/zoomable-image-gallery/ZoomableImageGallery.js +16 -7
  26. package/lib/module/zoomable-image-gallery/ZoomableImageGallery.js.map +1 -1
  27. package/lib/typescript/commonjs/context-menu/index.web.d.ts.map +1 -1
  28. package/lib/typescript/commonjs/image-aspect-ratio-cache/imageAspectRatioCache.d.ts +12 -0
  29. package/lib/typescript/commonjs/image-aspect-ratio-cache/imageAspectRatioCache.d.ts.map +1 -1
  30. package/lib/typescript/commonjs/image-aspect-ratio-cache/index.d.ts +2 -1
  31. package/lib/typescript/commonjs/image-aspect-ratio-cache/index.d.ts.map +1 -1
  32. package/lib/typescript/commonjs/overlay/index.d.ts +2 -2
  33. package/lib/typescript/commonjs/popover/index.web.d.ts.map +1 -1
  34. package/lib/typescript/commonjs/select/index.web.d.ts.map +1 -1
  35. package/lib/typescript/commonjs/zoomable-image-gallery/ZoomableImageGallery.d.ts.map +1 -1
  36. package/lib/typescript/module/context-menu/index.web.d.ts.map +1 -1
  37. package/lib/typescript/module/image-aspect-ratio-cache/imageAspectRatioCache.d.ts +12 -0
  38. package/lib/typescript/module/image-aspect-ratio-cache/imageAspectRatioCache.d.ts.map +1 -1
  39. package/lib/typescript/module/image-aspect-ratio-cache/index.d.ts +2 -1
  40. package/lib/typescript/module/image-aspect-ratio-cache/index.d.ts.map +1 -1
  41. package/lib/typescript/module/overlay/index.d.ts +2 -2
  42. package/lib/typescript/module/popover/index.web.d.ts.map +1 -1
  43. package/lib/typescript/module/select/index.web.d.ts.map +1 -1
  44. package/lib/typescript/module/zoomable-image-gallery/ZoomableImageGallery.d.ts.map +1 -1
  45. package/package.json +1 -1
  46. package/src/__tests__/imageIntrinsicSize.test.ts +47 -0
  47. package/src/__tests__/pointer-events-style-form.test.ts +24 -0
  48. package/src/context-menu/index.web.tsx +2 -1
  49. package/src/image-aspect-ratio-cache/imageAspectRatioCache.ts +18 -0
  50. package/src/image-aspect-ratio-cache/index.ts +2 -0
  51. package/src/overlay/index.tsx +2 -2
  52. package/src/popover/index.web.tsx +2 -1
  53. package/src/select/index.web.tsx +2 -1
  54. package/src/zoomable-image-gallery/ZoomableImageGallery.tsx +19 -6
@@ -1 +1 @@
1
- {"version":3,"file":"index.web.d.ts","sourceRoot":"","sources":["../../../../src/select/index.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8D,MAAM,OAAO,CAAC;AAenF,OAAO,EAA0C,oBAAoB,EAAE,MAAM,UAAU,CAAC;AACxF,OAAO,KAAK,EACV,kBAAkB,EAClB,eAAe,EACf,wBAAwB,EACxB,eAAe,EACf,mBAAmB,EACnB,WAAW,EAEX,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,oBAAoB,EAAE,CAAC;AA6BhC,wBAAgB,MAAM,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,EAAE,WAAW,2CAgB/E;AAMD,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,kBAAkB,yTAuDpE;AAMD,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EAAE,YAAY,EACtB,WAAW,EACX,KAAK,GACN,EAAE,gBAAgB,2CAkBlB;AAMD,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,eAAe,2CAGpD;AAMD,wBAAgB,aAAa,CAAC,CAAC,EAAE,EAC/B,KAAK,EACL,UAAU,EACV,KAA0B,EAC1B,cAA0C,GAC3C,EAAE,kBAAkB,CAAC,CAAC,CAAC,kDAmCvB;AAMD,wBAAgB,UAAU,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,eAAe,2CAyC1E;AAMD,wBAAgB,cAAc,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,mBAAmB,2CAMtE;AAMD,wBAAgB,mBAAmB,CAAC,EAAE,IAAI,EAAE,aAAyB,EAAE,EAAE,wBAAwB,2CAYhG;AAMD,wBAAgB,eAAe,4CAW9B"}
1
+ {"version":3,"file":"index.web.d.ts","sourceRoot":"","sources":["../../../../src/select/index.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8D,MAAM,OAAO,CAAC;AAgBnF,OAAO,EAA0C,oBAAoB,EAAE,MAAM,UAAU,CAAC;AACxF,OAAO,KAAK,EACV,kBAAkB,EAClB,eAAe,EACf,wBAAwB,EACxB,eAAe,EACf,mBAAmB,EACnB,WAAW,EAEX,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,oBAAoB,EAAE,CAAC;AA6BhC,wBAAgB,MAAM,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,EAAE,WAAW,2CAgB/E;AAMD,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,kBAAkB,yTAuDpE;AAMD,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EAAE,YAAY,EACtB,WAAW,EACX,KAAK,GACN,EAAE,gBAAgB,2CAkBlB;AAMD,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,eAAe,2CAGpD;AAMD,wBAAgB,aAAa,CAAC,CAAC,EAAE,EAC/B,KAAK,EACL,UAAU,EACV,KAA0B,EAC1B,cAA0C,GAC3C,EAAE,kBAAkB,CAAC,CAAC,CAAC,kDAmCvB;AAMD,wBAAgB,UAAU,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,eAAe,2CAyC1E;AAMD,wBAAgB,cAAc,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,mBAAmB,2CAMtE;AAMD,wBAAgB,mBAAmB,CAAC,EAAE,IAAI,EAAE,aAAyB,EAAE,EAAE,wBAAwB,2CAYhG;AAMD,wBAAgB,eAAe,4CAW9B"}
@@ -1 +1 @@
1
- {"version":3,"file":"ZoomableImageGallery.d.ts","sourceRoot":"","sources":["../../../../src/zoomable-image-gallery/ZoomableImageGallery.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAmEjF,OAAO,KAAK,EAGV,0BAA0B,EAC1B,yBAAyB,EAC1B,MAAM,SAAS,CAAC;AAo6BjB,eAAO,MAAM,oBAAoB,8GAA4B,CAAC;AAyK9D,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"ZoomableImageGallery.d.ts","sourceRoot":"","sources":["../../../../src/zoomable-image-gallery/ZoomableImageGallery.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAoEjF,OAAO,KAAK,EAGV,0BAA0B,EAC1B,yBAAyB,EAC1B,MAAM,SAAS,CAAC;AAg7BjB,eAAO,MAAM,oBAAoB,8GAA4B,CAAC;AAyK9D,eAAe,oBAAoB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.web.d.ts","sourceRoot":"","sources":["../../../../src/context-menu/index.web.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAQN,MAAM,OAAO,CAAC;AAWf,OAAO,KAAK,EAEV,uBAAuB,EACvB,qBAAqB,EACrB,wBAAwB,EACxB,oBAAoB,EACpB,wBAAwB,EACxB,uBAAuB,EAExB,MAAM,SAAS,CAAC;AA+BjB,wBAAgB,WAAW,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,2CA2BtE;AAWD,wBAAgB,kBAAkB,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,uBAAuB,2CA4C3F;AAMD,wBAAgB,kBAAkB,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,uBAAuB,kDA6C9E;AAMD,wBAAgB,eAAe,CAAC,EAC9B,QAAQ,EACR,KAAK,EACL,OAAO,EACP,QAAgB,EAChB,KAAK,GACN,EAAE,oBAAoB,2CA+CtB;AAMD,wBAAgB,mBAAmB,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,wBAAwB,2CAiBhF;AAMD,wBAAgB,mBAAmB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,wBAAwB,2CAU3E;AAMD,wBAAgB,gBAAgB,CAAC,EAAE,QAAQ,EAAE,EAAE,qBAAqB,2CAEnE;AAMD,wBAAgB,kBAAkB,4CAWjC"}
1
+ {"version":3,"file":"index.web.d.ts","sourceRoot":"","sources":["../../../../src/context-menu/index.web.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAQN,MAAM,OAAO,CAAC;AAYf,OAAO,KAAK,EAEV,uBAAuB,EACvB,qBAAqB,EACrB,wBAAwB,EACxB,oBAAoB,EACpB,wBAAwB,EACxB,uBAAuB,EAExB,MAAM,SAAS,CAAC;AA+BjB,wBAAgB,WAAW,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,2CA2BtE;AAWD,wBAAgB,kBAAkB,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,uBAAuB,2CA4C3F;AAMD,wBAAgB,kBAAkB,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,uBAAuB,kDA6C9E;AAMD,wBAAgB,eAAe,CAAC,EAC9B,QAAQ,EACR,KAAK,EACL,OAAO,EACP,QAAgB,EAChB,KAAK,GACN,EAAE,oBAAoB,2CA+CtB;AAMD,wBAAgB,mBAAmB,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,wBAAwB,2CAiBhF;AAMD,wBAAgB,mBAAmB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,wBAAwB,2CAU3E;AAMD,wBAAgB,gBAAgB,CAAC,EAAE,QAAQ,EAAE,EAAE,qBAAqB,2CAEnE;AAMD,wBAAgB,kBAAkB,4CAWjC"}
@@ -1,5 +1,17 @@
1
1
  /** Fallback ratio used when a remote image's intrinsic size cannot be read. */
2
2
  export declare const DEFAULT_ASPECT_RATIO: number;
3
+ /**
4
+ * Intrinsic pixel size, recorded whenever we had to read it anyway (the
5
+ * `Image.getSize` behind `fetchAspectRatio`). A viewer needs it to avoid
6
+ * blowing a small image up past its own resolution — a ratio alone cannot say
7
+ * how big "big" is allowed to be.
8
+ */
9
+ export interface IntrinsicSize {
10
+ width: number;
11
+ height: number;
12
+ }
13
+ /** Intrinsic size for `uri`, when it has already been measured. */
14
+ export declare const getIntrinsicSize: (uri: string) => IntrinsicSize | undefined;
3
15
  export declare const getAspectRatio: (uri: string) => number | undefined;
4
16
  export declare const hasAspectRatio: (uri: string) => boolean;
5
17
  export declare const setAspectRatio: (uri: string, ratio: number) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"imageAspectRatioCache.d.ts","sourceRoot":"","sources":["../../../../src/image-aspect-ratio-cache/imageAspectRatioCache.ts"],"names":[],"mappings":"AAeA,+EAA+E;AAC/E,eAAO,MAAM,oBAAoB,QAAQ,CAAC;AAI1C,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,SAAsC,CAAC;AAE7F,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,KAAG,OAAoC,CAAC;AAElF,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,EAAE,OAAO,MAAM,KAAG,IAI3D,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAAI,KAAK,MAAM,KAAG,OAAO,CAAC,MAAM,CAwB5D,CAAC"}
1
+ {"version":3,"file":"imageAspectRatioCache.d.ts","sourceRoot":"","sources":["../../../../src/image-aspect-ratio-cache/imageAspectRatioCache.ts"],"names":[],"mappings":"AAeA,+EAA+E;AAC/E,eAAO,MAAM,oBAAoB,QAAQ,CAAC;AAI1C;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAID,mEAAmE;AACnE,eAAO,MAAM,gBAAgB,GAAI,KAAK,MAAM,KAAG,aAAa,GAAG,SAClC,CAAC;AAE9B,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,SAAsC,CAAC;AAE7F,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,KAAG,OAAoC,CAAC;AAElF,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,EAAE,OAAO,MAAM,KAAG,IAI3D,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAAI,KAAK,MAAM,KAAG,OAAO,CAAC,MAAM,CAyB5D,CAAC"}
@@ -1,2 +1,3 @@
1
- export { getAspectRatio, hasAspectRatio, setAspectRatio, fetchAspectRatio, DEFAULT_ASPECT_RATIO, } from './imageAspectRatioCache';
1
+ export type { IntrinsicSize } from './imageAspectRatioCache';
2
+ export { getIntrinsicSize, getAspectRatio, hasAspectRatio, setAspectRatio, fetchAspectRatio, DEFAULT_ASPECT_RATIO, } from './imageAspectRatioCache';
2
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/image-aspect-ratio-cache/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/image-aspect-ratio-cache/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,yBAAyB,CAAC"}
@@ -45,9 +45,9 @@ import { View, type StyleProp, type ViewStyle } from 'react-native';
45
45
  * One blur radius for every Bloom overlay. Surfaces differ in what they show,
46
46
  * not in how the app behind them recedes.
47
47
  */
48
- export declare const BACKDROP_BLUR_INTENSITY = 40;
48
+ export declare const BACKDROP_BLUR_INTENSITY = 80;
49
49
  /** Dim laid over the blur — the blur alone does not give enough contrast. */
50
- export declare const BACKDROP_DIM_OPACITY = 0.45;
50
+ export declare const BACKDROP_DIM_OPACITY = 0.55;
51
51
  export interface OverlayRootProps {
52
52
  children?: ReactNode;
53
53
  style?: StyleProp<ViewStyle>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.web.d.ts","sourceRoot":"","sources":["../../../../src/popover/index.web.tsx"],"names":[],"mappings":"AAgBA,OAAO,EAAkB,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9D,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EAEnB,YAAY,EACZ,mBAAmB,EACpB,MAAM,SAAS,CAAC;AAEjB,YAAY,EACV,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,YAAY,EACZ,gBAAgB,EAChB,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAI7B;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,mBAAmB,CAoBvD;AASD,wBAAgB,OAAO,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,YAAY,2CAkD1D;AAED,wBAAgB,cAAc,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,mBAAmB,2CA+BtE;AAuCD,wBAAgB,cAAc,CAAC,EAC7B,QAAQ,EACR,KAAiB,EACjB,SAA0B,EAC1B,MAAU,EACV,QAAQ,EACR,QAAc,EACd,WAAkB,EAClB,KAAK,EACL,MAAM,GACP,EAAE,mBAAmB,kDAmGrB"}
1
+ {"version":3,"file":"index.web.d.ts","sourceRoot":"","sources":["../../../../src/popover/index.web.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAAkB,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9D,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EAEnB,YAAY,EACZ,mBAAmB,EACpB,MAAM,SAAS,CAAC;AAEjB,YAAY,EACV,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,YAAY,EACZ,gBAAgB,EAChB,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAI7B;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,mBAAmB,CAoBvD;AASD,wBAAgB,OAAO,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,YAAY,2CAkD1D;AAED,wBAAgB,cAAc,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,mBAAmB,2CA+BtE;AAuCD,wBAAgB,cAAc,CAAC,EAC7B,QAAQ,EACR,KAAiB,EACjB,SAA0B,EAC1B,MAAU,EACV,QAAQ,EACR,QAAc,EACd,WAAkB,EAClB,KAAK,EACL,MAAM,GACP,EAAE,mBAAmB,kDAmGrB"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.web.d.ts","sourceRoot":"","sources":["../../../../src/select/index.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8D,MAAM,OAAO,CAAC;AAenF,OAAO,EAA0C,oBAAoB,EAAE,MAAM,UAAU,CAAC;AACxF,OAAO,KAAK,EACV,kBAAkB,EAClB,eAAe,EACf,wBAAwB,EACxB,eAAe,EACf,mBAAmB,EACnB,WAAW,EAEX,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,oBAAoB,EAAE,CAAC;AA6BhC,wBAAgB,MAAM,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,EAAE,WAAW,2CAgB/E;AAMD,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,kBAAkB,yTAuDpE;AAMD,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EAAE,YAAY,EACtB,WAAW,EACX,KAAK,GACN,EAAE,gBAAgB,2CAkBlB;AAMD,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,eAAe,2CAGpD;AAMD,wBAAgB,aAAa,CAAC,CAAC,EAAE,EAC/B,KAAK,EACL,UAAU,EACV,KAA0B,EAC1B,cAA0C,GAC3C,EAAE,kBAAkB,CAAC,CAAC,CAAC,kDAmCvB;AAMD,wBAAgB,UAAU,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,eAAe,2CAyC1E;AAMD,wBAAgB,cAAc,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,mBAAmB,2CAMtE;AAMD,wBAAgB,mBAAmB,CAAC,EAAE,IAAI,EAAE,aAAyB,EAAE,EAAE,wBAAwB,2CAYhG;AAMD,wBAAgB,eAAe,4CAW9B"}
1
+ {"version":3,"file":"index.web.d.ts","sourceRoot":"","sources":["../../../../src/select/index.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8D,MAAM,OAAO,CAAC;AAgBnF,OAAO,EAA0C,oBAAoB,EAAE,MAAM,UAAU,CAAC;AACxF,OAAO,KAAK,EACV,kBAAkB,EAClB,eAAe,EACf,wBAAwB,EACxB,eAAe,EACf,mBAAmB,EACnB,WAAW,EAEX,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,oBAAoB,EAAE,CAAC;AA6BhC,wBAAgB,MAAM,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,EAAE,WAAW,2CAgB/E;AAMD,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,kBAAkB,yTAuDpE;AAMD,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EAAE,YAAY,EACtB,WAAW,EACX,KAAK,GACN,EAAE,gBAAgB,2CAkBlB;AAMD,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,eAAe,2CAGpD;AAMD,wBAAgB,aAAa,CAAC,CAAC,EAAE,EAC/B,KAAK,EACL,UAAU,EACV,KAA0B,EAC1B,cAA0C,GAC3C,EAAE,kBAAkB,CAAC,CAAC,CAAC,kDAmCvB;AAMD,wBAAgB,UAAU,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,eAAe,2CAyC1E;AAMD,wBAAgB,cAAc,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,mBAAmB,2CAMtE;AAMD,wBAAgB,mBAAmB,CAAC,EAAE,IAAI,EAAE,aAAyB,EAAE,EAAE,wBAAwB,2CAYhG;AAMD,wBAAgB,eAAe,4CAW9B"}
@@ -1 +1 @@
1
- {"version":3,"file":"ZoomableImageGallery.d.ts","sourceRoot":"","sources":["../../../../src/zoomable-image-gallery/ZoomableImageGallery.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAmEjF,OAAO,KAAK,EAGV,0BAA0B,EAC1B,yBAAyB,EAC1B,MAAM,SAAS,CAAC;AAo6BjB,eAAO,MAAM,oBAAoB,8GAA4B,CAAC;AAyK9D,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"ZoomableImageGallery.d.ts","sourceRoot":"","sources":["../../../../src/zoomable-image-gallery/ZoomableImageGallery.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAoEjF,OAAO,KAAK,EAGV,0BAA0B,EAC1B,yBAAyB,EAC1B,MAAM,SAAS,CAAC;AAg7BjB,eAAO,MAAM,oBAAoB,8GAA4B,CAAC;AAyK9D,eAAe,oBAAoB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxyhq/bloom",
3
- "version": "0.59.0",
3
+ "version": "0.61.0",
4
4
  "description": "Bloom UI — Oxy ecosystem component library for React Native + Expo + Web",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
@@ -0,0 +1,47 @@
1
+ // The fullscreen viewer must not blow an image up past its own resolution — a
2
+ // 512px avatar or a small thumbnail filling the viewport just renders soft.
3
+ // A ratio alone cannot express that ceiling, so the shared cache records the
4
+ // intrinsic size it had to read anyway (the `Image.getSize` behind
5
+ // `fetchAspectRatio`) and the viewer clamps its fit box to it.
6
+
7
+ const getSize = jest.fn();
8
+
9
+ jest.mock('react-native', () => ({
10
+ Image: { getSize: (...args: unknown[]) => getSize(...args) },
11
+ }));
12
+
13
+ import {
14
+ DEFAULT_ASPECT_RATIO,
15
+ fetchAspectRatio,
16
+ getAspectRatio,
17
+ getIntrinsicSize,
18
+ } from '../image-aspect-ratio-cache';
19
+
20
+ describe('intrinsic size cache', () => {
21
+ beforeEach(() => {
22
+ getSize.mockReset();
23
+ });
24
+
25
+ it('records the measured pixel size alongside the ratio', async () => {
26
+ const uri = 'https://cdn.example/avatar-512.jpg';
27
+ getSize.mockImplementation((_uri: string, ok: (w: number, h: number) => void) => ok(512, 512));
28
+
29
+ const ratio = await fetchAspectRatio(uri);
30
+
31
+ expect(ratio).toBe(1);
32
+ expect(getAspectRatio(uri)).toBe(1);
33
+ expect(getIntrinsicSize(uri)).toEqual({ width: 512, height: 512 });
34
+ });
35
+
36
+ it('leaves no size behind when the image cannot be measured', async () => {
37
+ const uri = 'https://cdn.example/broken.jpg';
38
+ getSize.mockImplementation((_uri: string, _ok: unknown, fail: () => void) => fail());
39
+
40
+ const ratio = await fetchAspectRatio(uri);
41
+
42
+ expect(ratio).toBe(DEFAULT_ASPECT_RATIO);
43
+ // No measurement means no ceiling — the viewer falls back to its fit box
44
+ // rather than clamping to a guess.
45
+ expect(getIntrinsicSize(uri)).toBeUndefined();
46
+ });
47
+ });
@@ -43,6 +43,30 @@ describe('pointerEvents style-object form', () => {
43
43
  expect(files.some((f) => f.endsWith(join('overlay', 'index.tsx')))).toBe(true);
44
44
  });
45
45
 
46
+ // Every dismiss scrim is the shared `Backdrop`. The dropdown surfaces used to
47
+ // render a bare full-screen `Pressable` instead — a fourth copy of the idea,
48
+ // and a fully transparent one, so menus dismissed but never dimmed or blurred
49
+ // while dialogs and sheets did.
50
+ it('routes every backdrop-styled element through <Backdrop>', () => {
51
+ const offenders: string[] = [];
52
+
53
+ for (const file of files) {
54
+ const source = readFileSync(file, 'utf8');
55
+ // Every JSX element that takes the file's `styles.backdrop`, resolved back
56
+ // to the tag that opens it.
57
+ for (const match of source.matchAll(/style=\{(?:\[)?styles\.backdrop\b/g)) {
58
+ const opener = source.slice(0, match.index).lastIndexOf('<');
59
+ const tag = /^<([A-Za-z.]+)/.exec(source.slice(opener))?.[1] ?? '?';
60
+ if (tag !== 'Backdrop' && tag !== 'AnimatedBackdrop') {
61
+ const line = source.slice(0, match.index).split('\n').length;
62
+ offenders.push(`${file.slice(SRC.length + 1)}:${line} <${tag}> uses styles.backdrop`);
63
+ }
64
+ }
65
+ }
66
+
67
+ expect(offenders).toEqual([]);
68
+ });
69
+
46
70
  it('never uses the RN-only values as styles — pass them as the prop', () => {
47
71
  const offenders = files
48
72
  .flatMap((file) =>
@@ -17,6 +17,7 @@ import { Pressable, StyleSheet, View } from 'react-native';
17
17
 
18
18
  import { useTheme } from '../theme/use-theme';
19
19
  import { Text } from '../typography';
20
+ import { Backdrop } from '../overlay';
20
21
  import { Portal } from '../portal/index.web';
21
22
  import { useInteractionState } from '../hooks/useInteractionState';
22
23
  import { createOverlayZIndex } from '../styles/z-index';
@@ -172,7 +173,7 @@ export function ContextMenuContent({ children, style }: ContextMenuContentProps)
172
173
 
173
174
  return (
174
175
  <Portal>
175
- <Pressable
176
+ <Backdrop
176
177
  style={styles.backdrop}
177
178
  onPress={close}
178
179
  accessibilityLabel="Close context menu"
@@ -18,6 +18,23 @@ export const DEFAULT_ASPECT_RATIO = 4 / 3;
18
18
 
19
19
  const aspectRatioCache = new Map<string, number>();
20
20
 
21
+ /**
22
+ * Intrinsic pixel size, recorded whenever we had to read it anyway (the
23
+ * `Image.getSize` behind `fetchAspectRatio`). A viewer needs it to avoid
24
+ * blowing a small image up past its own resolution — a ratio alone cannot say
25
+ * how big "big" is allowed to be.
26
+ */
27
+ export interface IntrinsicSize {
28
+ width: number;
29
+ height: number;
30
+ }
31
+
32
+ const intrinsicSizeCache = new Map<string, IntrinsicSize>();
33
+
34
+ /** Intrinsic size for `uri`, when it has already been measured. */
35
+ export const getIntrinsicSize = (uri: string): IntrinsicSize | undefined =>
36
+ intrinsicSizeCache.get(uri);
37
+
21
38
  export const getAspectRatio = (uri: string): number | undefined => aspectRatioCache.get(uri);
22
39
 
23
40
  export const hasAspectRatio = (uri: string): boolean => aspectRatioCache.has(uri);
@@ -47,6 +64,7 @@ export const fetchAspectRatio = (uri: string): Promise<number> => {
47
64
  if (width > 0 && height > 0) {
48
65
  const ratio = width / height;
49
66
  aspectRatioCache.set(uri, ratio);
67
+ intrinsicSizeCache.set(uri, { width, height });
50
68
  resolve(ratio);
51
69
  return;
52
70
  }
@@ -1,4 +1,6 @@
1
+ export type { IntrinsicSize } from './imageAspectRatioCache';
1
2
  export {
3
+ getIntrinsicSize,
2
4
  getAspectRatio,
3
5
  hasAspectRatio,
4
6
  setAspectRatio,
@@ -56,9 +56,9 @@ import { WEB_POSITION_FIXED } from '../styles/web-view-style';
56
56
  * One blur radius for every Bloom overlay. Surfaces differ in what they show,
57
57
  * not in how the app behind them recedes.
58
58
  */
59
- export const BACKDROP_BLUR_INTENSITY = 40;
59
+ export const BACKDROP_BLUR_INTENSITY = 80;
60
60
  /** Dim laid over the blur — the blur alone does not give enough contrast. */
61
- export const BACKDROP_DIM_OPACITY = 0.45;
61
+ export const BACKDROP_DIM_OPACITY = 0.55;
62
62
 
63
63
  export interface OverlayRootProps {
64
64
  children?: ReactNode;
@@ -10,6 +10,7 @@ import React, {
10
10
  import { Pressable, StyleSheet, View } from 'react-native';
11
11
 
12
12
  import { useTheme } from '../theme/use-theme';
13
+ import { Backdrop } from '../overlay';
13
14
  import { Portal } from '../portal/index.web';
14
15
  import { createOverlayZIndex } from '../styles/z-index';
15
16
  import { WEB_POSITION_FIXED } from '../styles/web-view-style';
@@ -262,7 +263,7 @@ export function PopoverContent({
262
263
  return (
263
264
  <Portal>
264
265
  {dismissible ? (
265
- <Pressable
266
+ <Backdrop
266
267
  style={styles.backdrop}
267
268
  onPress={() => control.close()}
268
269
  accessibilityLabel="Dismiss popover"
@@ -3,6 +3,7 @@ import { Pressable, StyleSheet, View } from 'react-native';
3
3
 
4
4
  import { useTheme } from '../theme/use-theme';
5
5
  import { Text } from '../typography';
6
+ import { Backdrop } from '../overlay';
6
7
  import { Portal } from '../portal/index.web';
7
8
  import { createOverlayZIndex } from '../styles/z-index';
8
9
  import { WEB_POSITION_FIXED } from '../styles/web-view-style';
@@ -188,7 +189,7 @@ export function SelectContent<T>({
188
189
 
189
190
  return (
190
191
  <Portal>
191
- <Pressable
192
+ <Backdrop
192
193
  style={styles.backdrop}
193
194
  onPress={ctx.close}
194
195
  accessibilityLabel="Close selection"
@@ -40,6 +40,7 @@ import { Z_INDEX } from '../styles/z-index';
40
40
  import { WEB_POSITION_FIXED, type WebCssStyle } from '../styles/web-view-style';
41
41
  import {
42
42
  getAspectRatio,
43
+ getIntrinsicSize,
43
44
  fetchAspectRatio,
44
45
  DEFAULT_ASPECT_RATIO,
45
46
  } from '../image-aspect-ratio-cache';
@@ -216,9 +217,12 @@ const ZoomableImageGalleryInner = React.forwardRef<ZoomableImageGalleryHandle, Z
216
217
  [SCREEN_WIDTH, SCREEN_HEIGHT]
217
218
  );
218
219
 
219
- // Compute the largest width/height for `ratio` that fits inside `fitBox`
220
- // without cropping (contain).
221
- const fitForRatio = useCallback((ratio: number): FittedSize => {
220
+ // Largest width/height for `ratio` that fits inside `fitBox` without cropping
221
+ // (contain), never exceeding the image's own resolution: filling the viewport
222
+ // with a 512px avatar or a small thumbnail just renders it soft. `uri` is what
223
+ // lets us look the intrinsic size up; without it (not measured yet) the fit
224
+ // box wins and the clamp applies on the next frame.
225
+ const fitForRatio = useCallback((ratio: number, uri?: string): FittedSize => {
222
226
  const safeRatio = ratio > 0 && Number.isFinite(ratio) ? ratio : DEFAULT_ASPECT_RATIO;
223
227
  let width = fitBox.width;
224
228
  let height = width / safeRatio;
@@ -226,6 +230,11 @@ const ZoomableImageGalleryInner = React.forwardRef<ZoomableImageGalleryHandle, Z
226
230
  height = fitBox.height;
227
231
  width = height * safeRatio;
228
232
  }
233
+ const intrinsic = uri ? getIntrinsicSize(uri) : undefined;
234
+ if (intrinsic && intrinsic.width > 0 && width > intrinsic.width) {
235
+ width = intrinsic.width;
236
+ height = width / safeRatio;
237
+ }
229
238
  return { width, height };
230
239
  }, [fitBox]);
231
240
 
@@ -234,7 +243,11 @@ const ZoomableImageGalleryInner = React.forwardRef<ZoomableImageGalleryHandle, Z
234
243
  // after swiping it tracks the viewed image so the collapse-on-dismiss renders
235
244
  // and flies back the image actually on screen.
236
245
  const activeRatio = pageRatios[activeIndex] ?? openRatio;
237
- const activeFit = useMemo(() => fitForRatio(activeRatio), [fitForRatio, activeRatio]);
246
+ const activeUri = images[activeIndex]?.uri;
247
+ const activeFit = useMemo(
248
+ () => fitForRatio(activeRatio, activeUri),
249
+ [fitForRatio, activeRatio, activeUri],
250
+ );
238
251
 
239
252
  // Alt text (accessibility description) of the image currently on screen, shown
240
253
  // as a caption at the bottom of the viewer (Bluesky-style lightbox footer).
@@ -391,7 +404,7 @@ const ZoomableImageGalleryInner = React.forwardRef<ZoomableImageGalleryHandle, Z
391
404
  // animation grows it from the thumbnail's footprint (scale < 1) up to 1,
392
405
  // mirroring the avatar's small→big scale. The initial scale is the ratio
393
406
  // of the thumbnail width to the fitted width.
394
- const fitted = fitForRatio(ratio);
407
+ const fitted = fitForRatio(ratio, target.uri);
395
408
  const centerX = SCREEN_WIDTH / 2;
396
409
  const centerY = SCREEN_HEIGHT / 2;
397
410
  if (rect && rect.width > 0) {
@@ -829,7 +842,7 @@ const ZoomableImageGalleryInner = React.forwardRef<ZoomableImageGalleryHandle, Z
829
842
  >
830
843
  {images.map((img, idx) => {
831
844
  const ratio = pageRatios[idx] ?? getAspectRatio(img.uri) ?? DEFAULT_ASPECT_RATIO;
832
- const fit = fitForRatio(ratio);
845
+ const fit = fitForRatio(ratio, img.uri);
833
846
  // Only the active page is zoomable + gesture-wrapped (double-tap
834
847
  // / single-tap dismiss / pinch / pan). Off-screen pages stay a
835
848
  // plain image; the active image handles its own tap-to-dismiss