@oxyhq/bloom 0.50.2 → 0.51.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +89 -0
- package/README.md +12 -7
- package/lib/commonjs/avatar-group/AvatarGroup.web.js +2 -1
- package/lib/commonjs/avatar-group/AvatarGroup.web.js.map +1 -1
- package/lib/commonjs/bottom-sheet/index.web.js +2 -1
- package/lib/commonjs/bottom-sheet/index.web.js.map +1 -1
- package/lib/commonjs/context-menu/index.web.js +3 -2
- package/lib/commonjs/context-menu/index.web.js.map +1 -1
- package/lib/commonjs/dialog/Dialog.web.js +4 -3
- package/lib/commonjs/dialog/Dialog.web.js.map +1 -1
- package/lib/commonjs/frosted-icon-button/shared.js +1 -1
- package/lib/commonjs/index.js +90 -83
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.web.js +116 -109
- package/lib/commonjs/index.web.js.map +1 -1
- package/lib/commonjs/menu/index.web.js +2 -1
- package/lib/commonjs/menu/index.web.js.map +1 -1
- package/lib/commonjs/popover/index.web.js +3 -2
- package/lib/commonjs/popover/index.web.js.map +1 -1
- package/lib/commonjs/portal/index.js +4 -1
- package/lib/commonjs/portal/index.js.map +1 -1
- package/lib/commonjs/progressive-blur/index.js +79 -0
- package/lib/commonjs/progressive-blur/index.js.map +1 -0
- package/lib/commonjs/progressive-blur/index.web.js +67 -0
- package/lib/commonjs/progressive-blur/index.web.js.map +1 -0
- package/lib/commonjs/progressive-blur/shared.js +66 -0
- package/lib/commonjs/progressive-blur/shared.js.map +1 -0
- package/lib/commonjs/progressive-blur/types.js +6 -0
- package/lib/commonjs/progressive-blur/types.js.map +1 -0
- package/lib/commonjs/select/index.web.js +2 -1
- package/lib/commonjs/select/index.web.js.map +1 -1
- package/lib/commonjs/styles/web-view-style.js +26 -0
- package/lib/commonjs/styles/web-view-style.js.map +1 -0
- package/lib/commonjs/tab-bar/TabBarBase.js +415 -0
- package/lib/commonjs/tab-bar/TabBarBase.js.map +1 -0
- package/lib/commonjs/tab-bar/expo-router/RouterTabBar.js +83 -0
- package/lib/commonjs/tab-bar/expo-router/RouterTabBar.js.map +1 -0
- package/lib/commonjs/tab-bar/expo-router/fading-tab-screen.js +119 -0
- package/lib/commonjs/tab-bar/expo-router/fading-tab-screen.js.map +1 -0
- package/lib/commonjs/tab-bar/expo-router/index.js +26 -0
- package/lib/commonjs/tab-bar/expo-router/index.js.map +1 -0
- package/lib/commonjs/tab-bar/glyph.js +43 -0
- package/lib/commonjs/tab-bar/glyph.js.map +1 -0
- package/lib/commonjs/tab-bar/glyph.native.js +55 -0
- package/lib/commonjs/tab-bar/glyph.native.js.map +1 -0
- package/lib/commonjs/tab-bar/index.js +65 -0
- package/lib/commonjs/tab-bar/index.js.map +1 -0
- package/lib/commonjs/tab-bar/index.web.js +67 -0
- package/lib/commonjs/tab-bar/index.web.js.map +1 -0
- package/lib/commonjs/tab-bar/minimize-context.js +127 -0
- package/lib/commonjs/tab-bar/minimize-context.js.map +1 -0
- package/lib/commonjs/tab-bar/shared.js +139 -0
- package/lib/commonjs/tab-bar/shared.js.map +1 -0
- package/lib/commonjs/tab-bar/surface-solid.js +43 -0
- package/lib/commonjs/tab-bar/surface-solid.js.map +1 -0
- package/lib/commonjs/tab-bar/surface.js +13 -0
- package/lib/commonjs/tab-bar/surface.js.map +1 -0
- package/lib/commonjs/tab-bar/surface.native.js +113 -0
- package/lib/commonjs/tab-bar/surface.native.js.map +1 -0
- package/lib/commonjs/tab-bar/surface.web.js +59 -0
- package/lib/commonjs/tab-bar/surface.web.js.map +1 -0
- package/lib/commonjs/tab-bar/types.js +6 -0
- package/lib/commonjs/tab-bar/types.js.map +1 -0
- package/lib/commonjs/toast/Positioner.js +117 -0
- package/lib/commonjs/toast/Positioner.js.map +1 -0
- package/lib/commonjs/toast/ToastContent.js +301 -0
- package/lib/commonjs/toast/ToastContent.js.map +1 -0
- package/lib/commonjs/toast/ToastHost.js +69 -0
- package/lib/commonjs/toast/ToastHost.js.map +1 -0
- package/lib/commonjs/toast/ToastHost.native.js +44 -0
- package/lib/commonjs/toast/ToastHost.native.js.map +1 -0
- package/lib/commonjs/toast/ToastIcon.js +57 -0
- package/lib/commonjs/toast/ToastIcon.js.map +1 -0
- package/lib/commonjs/toast/ToastRow.js +411 -0
- package/lib/commonjs/toast/ToastRow.js.map +1 -0
- package/lib/commonjs/toast/ToastSwipeHandler.js +189 -0
- package/lib/commonjs/toast/ToastSwipeHandler.js.map +1 -0
- package/lib/commonjs/toast/Toaster.js +205 -0
- package/lib/commonjs/toast/Toaster.js.map +1 -0
- package/lib/commonjs/toast/animations.js +274 -0
- package/lib/commonjs/toast/animations.js.map +1 -0
- package/lib/commonjs/toast/constants.js +56 -0
- package/lib/commonjs/toast/constants.js.map +1 -0
- package/lib/commonjs/toast/context.js +42 -0
- package/lib/commonjs/toast/context.js.map +1 -0
- package/lib/commonjs/toast/index.js +32 -126
- package/lib/commonjs/toast/index.js.map +1 -1
- package/lib/commonjs/toast/position-utils.js +115 -0
- package/lib/commonjs/toast/position-utils.js.map +1 -0
- package/lib/commonjs/toast/positioner-utils.js +141 -0
- package/lib/commonjs/toast/positioner-utils.js.map +1 -0
- package/lib/commonjs/toast/toast-comparator.js +28 -0
- package/lib/commonjs/toast/toast-comparator.js.map +1 -0
- package/lib/commonjs/toast/toast-fns.js +90 -0
- package/lib/commonjs/toast/toast-fns.js.map +1 -0
- package/lib/commonjs/toast/toast-store.js +352 -0
- package/lib/commonjs/toast/toast-store.js.map +1 -0
- package/lib/commonjs/toast/toast-timers.js +110 -0
- package/lib/commonjs/toast/toast-timers.js.map +1 -0
- package/lib/commonjs/toast/types.js +42 -0
- package/lib/commonjs/toast/types.js.map +1 -1
- package/lib/commonjs/toast/use-animated-target.js +57 -0
- package/lib/commonjs/toast/use-animated-target.js.map +1 -0
- package/lib/commonjs/toast/use-app-state.js +76 -0
- package/lib/commonjs/toast/use-app-state.js.map +1 -0
- package/lib/commonjs/toast/use-toast-colors.js +114 -0
- package/lib/commonjs/toast/use-toast-colors.js.map +1 -0
- package/lib/commonjs/toast/use-toast-position.js +40 -0
- package/lib/commonjs/toast/use-toast-position.js.map +1 -0
- package/lib/commonjs/tooltip/index.web.js +2 -1
- package/lib/commonjs/tooltip/index.web.js.map +1 -1
- package/lib/commonjs/zoomable-image-gallery/ZoomableImageGallery.js +20 -8
- package/lib/commonjs/zoomable-image-gallery/ZoomableImageGallery.js.map +1 -1
- package/lib/module/avatar-group/AvatarGroup.web.js +2 -1
- package/lib/module/avatar-group/AvatarGroup.web.js.map +1 -1
- package/lib/module/bottom-sheet/index.web.js +2 -1
- package/lib/module/bottom-sheet/index.web.js.map +1 -1
- package/lib/module/context-menu/index.web.js +3 -2
- package/lib/module/context-menu/index.web.js.map +1 -1
- package/lib/module/dialog/Dialog.web.js +4 -3
- package/lib/module/dialog/Dialog.web.js.map +1 -1
- package/lib/module/frosted-icon-button/shared.js +1 -1
- package/lib/module/index.js +3 -2
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +3 -2
- package/lib/module/index.web.js.map +1 -1
- package/lib/module/menu/index.web.js +2 -1
- package/lib/module/menu/index.web.js.map +1 -1
- package/lib/module/popover/index.web.js +3 -2
- package/lib/module/popover/index.web.js.map +1 -1
- package/lib/module/portal/index.js +4 -1
- package/lib/module/portal/index.js.map +1 -1
- package/lib/module/progressive-blur/index.js +74 -0
- package/lib/module/progressive-blur/index.js.map +1 -0
- package/lib/module/progressive-blur/index.web.js +62 -0
- package/lib/module/progressive-blur/index.web.js.map +1 -0
- package/lib/module/progressive-blur/shared.js +60 -0
- package/lib/module/progressive-blur/shared.js.map +1 -0
- package/lib/module/progressive-blur/types.js +4 -0
- package/lib/module/progressive-blur/types.js.map +1 -0
- package/lib/module/select/index.web.js +2 -1
- package/lib/module/select/index.web.js.map +1 -1
- package/lib/module/styles/web-view-style.js +22 -0
- package/lib/module/styles/web-view-style.js.map +1 -0
- package/lib/module/tab-bar/TabBarBase.js +408 -0
- package/lib/module/tab-bar/TabBarBase.js.map +1 -0
- package/lib/module/tab-bar/expo-router/RouterTabBar.js +78 -0
- package/lib/module/tab-bar/expo-router/RouterTabBar.js.map +1 -0
- package/lib/module/tab-bar/expo-router/fading-tab-screen.js +113 -0
- package/lib/module/tab-bar/expo-router/fading-tab-screen.js.map +1 -0
- package/lib/module/tab-bar/expo-router/index.js +15 -0
- package/lib/module/tab-bar/expo-router/index.js.map +1 -0
- package/lib/module/tab-bar/glyph.js +38 -0
- package/lib/module/tab-bar/glyph.js.map +1 -0
- package/lib/module/tab-bar/glyph.native.js +50 -0
- package/lib/module/tab-bar/glyph.native.js.map +1 -0
- package/lib/module/tab-bar/index.js +24 -0
- package/lib/module/tab-bar/index.js.map +1 -0
- package/lib/module/tab-bar/index.web.js +26 -0
- package/lib/module/tab-bar/index.web.js.map +1 -0
- package/lib/module/tab-bar/minimize-context.js +118 -0
- package/lib/module/tab-bar/minimize-context.js.map +1 -0
- package/lib/module/tab-bar/shared.js +132 -0
- package/lib/module/tab-bar/shared.js.map +1 -0
- package/lib/module/tab-bar/surface-solid.js +37 -0
- package/lib/module/tab-bar/surface-solid.js.map +1 -0
- package/lib/module/tab-bar/surface.js +31 -0
- package/lib/module/tab-bar/surface.js.map +1 -0
- package/lib/module/tab-bar/surface.native.js +109 -0
- package/lib/module/tab-bar/surface.native.js.map +1 -0
- package/lib/module/tab-bar/surface.web.js +53 -0
- package/lib/module/tab-bar/surface.web.js.map +1 -0
- package/lib/module/tab-bar/types.js +4 -0
- package/lib/module/tab-bar/types.js.map +1 -0
- package/lib/module/toast/Positioner.js +110 -0
- package/lib/module/toast/Positioner.js.map +1 -0
- package/lib/module/toast/ToastContent.js +295 -0
- package/lib/module/toast/ToastContent.js.map +1 -0
- package/lib/module/toast/ToastHost.js +63 -0
- package/lib/module/toast/ToastHost.js.map +1 -0
- package/lib/module/toast/ToastHost.native.js +38 -0
- package/lib/module/toast/ToastHost.native.js.map +1 -0
- package/lib/module/toast/ToastIcon.js +52 -0
- package/lib/module/toast/ToastIcon.js.map +1 -0
- package/lib/module/toast/ToastRow.js +407 -0
- package/lib/module/toast/ToastRow.js.map +1 -0
- package/lib/module/toast/ToastSwipeHandler.js +182 -0
- package/lib/module/toast/ToastSwipeHandler.js.map +1 -0
- package/lib/module/toast/Toaster.js +198 -0
- package/lib/module/toast/Toaster.js.map +1 -0
- package/lib/module/toast/animations.js +261 -0
- package/lib/module/toast/animations.js.map +1 -0
- package/lib/module/toast/constants.js +52 -0
- package/lib/module/toast/constants.js.map +1 -0
- package/lib/module/toast/context.js +34 -0
- package/lib/module/toast/context.js.map +1 -0
- package/lib/module/toast/index.js +27 -103
- package/lib/module/toast/index.js.map +1 -1
- package/lib/module/toast/position-utils.js +107 -0
- package/lib/module/toast/position-utils.js.map +1 -0
- package/lib/module/toast/positioner-utils.js +134 -0
- package/lib/module/toast/positioner-utils.js.map +1 -0
- package/lib/module/toast/toast-comparator.js +22 -0
- package/lib/module/toast/toast-comparator.js.map +1 -0
- package/lib/module/toast/toast-fns.js +85 -0
- package/lib/module/toast/toast-fns.js.map +1 -0
- package/lib/module/toast/toast-store.js +346 -0
- package/lib/module/toast/toast-store.js.map +1 -0
- package/lib/module/toast/toast-timers.js +104 -0
- package/lib/module/toast/toast-timers.js.map +1 -0
- package/lib/module/toast/types.js +38 -0
- package/lib/module/toast/types.js.map +1 -1
- package/lib/module/toast/use-animated-target.js +52 -0
- package/lib/module/toast/use-animated-target.js.map +1 -0
- package/lib/module/toast/use-app-state.js +70 -0
- package/lib/module/toast/use-app-state.js.map +1 -0
- package/lib/module/toast/use-toast-colors.js +109 -0
- package/lib/module/toast/use-toast-colors.js.map +1 -0
- package/lib/module/toast/use-toast-position.js +35 -0
- package/lib/module/toast/use-toast-position.js.map +1 -0
- package/lib/module/tooltip/index.web.js +2 -1
- package/lib/module/tooltip/index.web.js.map +1 -1
- package/lib/module/zoomable-image-gallery/ZoomableImageGallery.js +20 -8
- package/lib/module/zoomable-image-gallery/ZoomableImageGallery.js.map +1 -1
- package/lib/typescript/commonjs/avatar-group/AvatarGroup.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/benefit-list/types.d.ts +2 -1
- package/lib/typescript/commonjs/benefit-list/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/bottom-sheet/index.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/context-menu/index.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/dialog/Dialog.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/fab/types.d.ts +4 -2
- package/lib/typescript/commonjs/fab/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/frosted-icon-button/shared.d.ts +1 -1
- package/lib/typescript/commonjs/frosted-icon-button/types.d.ts +2 -1
- package/lib/typescript/commonjs/frosted-icon-button/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +2 -1
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.web.d.ts +2 -1
- package/lib/typescript/commonjs/index.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/menu/index.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/popover/index.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/portal/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/progressive-blur/index.d.ts +23 -0
- package/lib/typescript/commonjs/progressive-blur/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/progressive-blur/index.web.d.ts +30 -0
- package/lib/typescript/commonjs/progressive-blur/index.web.d.ts.map +1 -0
- package/lib/typescript/commonjs/progressive-blur/shared.d.ts +35 -0
- package/lib/typescript/commonjs/progressive-blur/shared.d.ts.map +1 -0
- package/lib/typescript/commonjs/progressive-blur/types.d.ts +21 -0
- package/lib/typescript/commonjs/progressive-blur/types.d.ts.map +1 -0
- package/lib/typescript/commonjs/select/index.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/styles/web-view-style.d.ts +21 -0
- package/lib/typescript/commonjs/styles/web-view-style.d.ts.map +1 -0
- package/lib/typescript/commonjs/tab-bar/TabBarBase.d.ts +36 -0
- package/lib/typescript/commonjs/tab-bar/TabBarBase.d.ts.map +1 -0
- package/lib/typescript/commonjs/tab-bar/expo-router/RouterTabBar.d.ts +59 -0
- package/lib/typescript/commonjs/tab-bar/expo-router/RouterTabBar.d.ts.map +1 -0
- package/lib/typescript/commonjs/tab-bar/expo-router/fading-tab-screen.d.ts +11 -0
- package/lib/typescript/commonjs/tab-bar/expo-router/fading-tab-screen.d.ts.map +1 -0
- package/lib/typescript/commonjs/tab-bar/expo-router/index.d.ts +14 -0
- package/lib/typescript/commonjs/tab-bar/expo-router/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/tab-bar/glyph.d.ts +6 -0
- package/lib/typescript/commonjs/tab-bar/glyph.d.ts.map +1 -0
- package/lib/typescript/commonjs/tab-bar/glyph.native.d.ts +6 -0
- package/lib/typescript/commonjs/tab-bar/glyph.native.d.ts.map +1 -0
- package/lib/typescript/commonjs/tab-bar/index.d.ts +12 -0
- package/lib/typescript/commonjs/tab-bar/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/tab-bar/index.web.d.ts +12 -0
- package/lib/typescript/commonjs/tab-bar/index.web.d.ts.map +1 -0
- package/lib/typescript/commonjs/tab-bar/minimize-context.d.ts +51 -0
- package/lib/typescript/commonjs/tab-bar/minimize-context.d.ts.map +1 -0
- package/lib/typescript/commonjs/tab-bar/shared.d.ts +93 -0
- package/lib/typescript/commonjs/tab-bar/shared.d.ts.map +1 -0
- package/lib/typescript/commonjs/tab-bar/surface-solid.d.ts +6 -0
- package/lib/typescript/commonjs/tab-bar/surface-solid.d.ts.map +1 -0
- package/lib/typescript/commonjs/tab-bar/surface.d.ts +29 -0
- package/lib/typescript/commonjs/tab-bar/surface.d.ts.map +1 -0
- package/lib/typescript/commonjs/tab-bar/surface.native.d.ts +6 -0
- package/lib/typescript/commonjs/tab-bar/surface.native.d.ts.map +1 -0
- package/lib/typescript/commonjs/tab-bar/surface.web.d.ts +6 -0
- package/lib/typescript/commonjs/tab-bar/surface.web.d.ts.map +1 -0
- package/lib/typescript/commonjs/tab-bar/types.d.ts +88 -0
- package/lib/typescript/commonjs/tab-bar/types.d.ts.map +1 -0
- package/lib/typescript/commonjs/toast/Positioner.d.ts +21 -0
- package/lib/typescript/commonjs/toast/Positioner.d.ts.map +1 -0
- package/lib/typescript/commonjs/toast/ToastContent.d.ts +14 -0
- package/lib/typescript/commonjs/toast/ToastContent.d.ts.map +1 -0
- package/lib/typescript/commonjs/toast/ToastHost.d.ts +6 -0
- package/lib/typescript/commonjs/toast/ToastHost.d.ts.map +1 -0
- package/lib/typescript/commonjs/toast/ToastHost.native.d.ts +6 -0
- package/lib/typescript/commonjs/toast/ToastHost.native.d.ts.map +1 -0
- package/lib/typescript/commonjs/toast/ToastIcon.d.ts +9 -0
- package/lib/typescript/commonjs/toast/ToastIcon.d.ts.map +1 -0
- package/lib/typescript/commonjs/toast/ToastRow.d.ts +80 -0
- package/lib/typescript/commonjs/toast/ToastRow.d.ts.map +1 -0
- package/lib/typescript/commonjs/toast/ToastSwipeHandler.d.ts +30 -0
- package/lib/typescript/commonjs/toast/ToastSwipeHandler.d.ts.map +1 -0
- package/lib/typescript/commonjs/toast/Toaster.d.ts +19 -0
- package/lib/typescript/commonjs/toast/Toaster.d.ts.map +1 -0
- package/lib/typescript/commonjs/toast/animations.d.ts +62 -0
- package/lib/typescript/commonjs/toast/animations.d.ts.map +1 -0
- package/lib/typescript/commonjs/toast/constants.d.ts +39 -0
- package/lib/typescript/commonjs/toast/constants.d.ts.map +1 -0
- package/lib/typescript/commonjs/toast/context.d.ts +19 -0
- package/lib/typescript/commonjs/toast/context.d.ts.map +1 -0
- package/lib/typescript/commonjs/toast/index.d.ts +23 -76
- package/lib/typescript/commonjs/toast/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/toast/position-utils.d.ts +30 -0
- package/lib/typescript/commonjs/toast/position-utils.d.ts.map +1 -0
- package/lib/typescript/commonjs/toast/positioner-utils.d.ts +72 -0
- package/lib/typescript/commonjs/toast/positioner-utils.d.ts.map +1 -0
- package/lib/typescript/commonjs/toast/toast-comparator.d.ts +12 -0
- package/lib/typescript/commonjs/toast/toast-comparator.d.ts.map +1 -0
- package/lib/typescript/commonjs/toast/toast-fns.d.ts +3 -0
- package/lib/typescript/commonjs/toast/toast-fns.d.ts.map +1 -0
- package/lib/typescript/commonjs/toast/toast-store.d.ts +52 -0
- package/lib/typescript/commonjs/toast/toast-store.d.ts.map +1 -0
- package/lib/typescript/commonjs/toast/toast-timers.d.ts +24 -0
- package/lib/typescript/commonjs/toast/toast-timers.d.ts.map +1 -0
- package/lib/typescript/commonjs/toast/types.d.ts +222 -5
- package/lib/typescript/commonjs/toast/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/toast/use-animated-target.d.ts +7 -0
- package/lib/typescript/commonjs/toast/use-animated-target.d.ts.map +1 -0
- package/lib/typescript/commonjs/toast/use-app-state.d.ts +18 -0
- package/lib/typescript/commonjs/toast/use-app-state.d.ts.map +1 -0
- package/lib/typescript/commonjs/toast/use-toast-colors.d.ts +22 -0
- package/lib/typescript/commonjs/toast/use-toast-colors.d.ts.map +1 -0
- package/lib/typescript/commonjs/toast/use-toast-position.d.ts +37 -0
- package/lib/typescript/commonjs/toast/use-toast-position.d.ts.map +1 -0
- package/lib/typescript/commonjs/tooltip/index.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/zoomable-image-gallery/ZoomableImageGallery.d.ts.map +1 -1
- package/lib/typescript/module/avatar-group/AvatarGroup.web.d.ts.map +1 -1
- package/lib/typescript/module/benefit-list/types.d.ts +2 -1
- package/lib/typescript/module/benefit-list/types.d.ts.map +1 -1
- package/lib/typescript/module/bottom-sheet/index.web.d.ts.map +1 -1
- package/lib/typescript/module/context-menu/index.web.d.ts.map +1 -1
- package/lib/typescript/module/dialog/Dialog.web.d.ts.map +1 -1
- package/lib/typescript/module/fab/types.d.ts +4 -2
- package/lib/typescript/module/fab/types.d.ts.map +1 -1
- package/lib/typescript/module/frosted-icon-button/shared.d.ts +1 -1
- package/lib/typescript/module/frosted-icon-button/types.d.ts +2 -1
- package/lib/typescript/module/frosted-icon-button/types.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +2 -1
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/index.web.d.ts +2 -1
- package/lib/typescript/module/index.web.d.ts.map +1 -1
- package/lib/typescript/module/menu/index.web.d.ts.map +1 -1
- package/lib/typescript/module/popover/index.web.d.ts.map +1 -1
- package/lib/typescript/module/portal/index.d.ts.map +1 -1
- package/lib/typescript/module/progressive-blur/index.d.ts +23 -0
- package/lib/typescript/module/progressive-blur/index.d.ts.map +1 -0
- package/lib/typescript/module/progressive-blur/index.web.d.ts +30 -0
- package/lib/typescript/module/progressive-blur/index.web.d.ts.map +1 -0
- package/lib/typescript/module/progressive-blur/shared.d.ts +35 -0
- package/lib/typescript/module/progressive-blur/shared.d.ts.map +1 -0
- package/lib/typescript/module/progressive-blur/types.d.ts +21 -0
- package/lib/typescript/module/progressive-blur/types.d.ts.map +1 -0
- package/lib/typescript/module/select/index.web.d.ts.map +1 -1
- package/lib/typescript/module/styles/web-view-style.d.ts +21 -0
- package/lib/typescript/module/styles/web-view-style.d.ts.map +1 -0
- package/lib/typescript/module/tab-bar/TabBarBase.d.ts +36 -0
- package/lib/typescript/module/tab-bar/TabBarBase.d.ts.map +1 -0
- package/lib/typescript/module/tab-bar/expo-router/RouterTabBar.d.ts +59 -0
- package/lib/typescript/module/tab-bar/expo-router/RouterTabBar.d.ts.map +1 -0
- package/lib/typescript/module/tab-bar/expo-router/fading-tab-screen.d.ts +11 -0
- package/lib/typescript/module/tab-bar/expo-router/fading-tab-screen.d.ts.map +1 -0
- package/lib/typescript/module/tab-bar/expo-router/index.d.ts +14 -0
- package/lib/typescript/module/tab-bar/expo-router/index.d.ts.map +1 -0
- package/lib/typescript/module/tab-bar/glyph.d.ts +6 -0
- package/lib/typescript/module/tab-bar/glyph.d.ts.map +1 -0
- package/lib/typescript/module/tab-bar/glyph.native.d.ts +6 -0
- package/lib/typescript/module/tab-bar/glyph.native.d.ts.map +1 -0
- package/lib/typescript/module/tab-bar/index.d.ts +12 -0
- package/lib/typescript/module/tab-bar/index.d.ts.map +1 -0
- package/lib/typescript/module/tab-bar/index.web.d.ts +12 -0
- package/lib/typescript/module/tab-bar/index.web.d.ts.map +1 -0
- package/lib/typescript/module/tab-bar/minimize-context.d.ts +51 -0
- package/lib/typescript/module/tab-bar/minimize-context.d.ts.map +1 -0
- package/lib/typescript/module/tab-bar/shared.d.ts +93 -0
- package/lib/typescript/module/tab-bar/shared.d.ts.map +1 -0
- package/lib/typescript/module/tab-bar/surface-solid.d.ts +6 -0
- package/lib/typescript/module/tab-bar/surface-solid.d.ts.map +1 -0
- package/lib/typescript/module/tab-bar/surface.d.ts +29 -0
- package/lib/typescript/module/tab-bar/surface.d.ts.map +1 -0
- package/lib/typescript/module/tab-bar/surface.native.d.ts +6 -0
- package/lib/typescript/module/tab-bar/surface.native.d.ts.map +1 -0
- package/lib/typescript/module/tab-bar/surface.web.d.ts +6 -0
- package/lib/typescript/module/tab-bar/surface.web.d.ts.map +1 -0
- package/lib/typescript/module/tab-bar/types.d.ts +88 -0
- package/lib/typescript/module/tab-bar/types.d.ts.map +1 -0
- package/lib/typescript/module/toast/Positioner.d.ts +21 -0
- package/lib/typescript/module/toast/Positioner.d.ts.map +1 -0
- package/lib/typescript/module/toast/ToastContent.d.ts +14 -0
- package/lib/typescript/module/toast/ToastContent.d.ts.map +1 -0
- package/lib/typescript/module/toast/ToastHost.d.ts +6 -0
- package/lib/typescript/module/toast/ToastHost.d.ts.map +1 -0
- package/lib/typescript/module/toast/ToastHost.native.d.ts +6 -0
- package/lib/typescript/module/toast/ToastHost.native.d.ts.map +1 -0
- package/lib/typescript/module/toast/ToastIcon.d.ts +9 -0
- package/lib/typescript/module/toast/ToastIcon.d.ts.map +1 -0
- package/lib/typescript/module/toast/ToastRow.d.ts +80 -0
- package/lib/typescript/module/toast/ToastRow.d.ts.map +1 -0
- package/lib/typescript/module/toast/ToastSwipeHandler.d.ts +30 -0
- package/lib/typescript/module/toast/ToastSwipeHandler.d.ts.map +1 -0
- package/lib/typescript/module/toast/Toaster.d.ts +19 -0
- package/lib/typescript/module/toast/Toaster.d.ts.map +1 -0
- package/lib/typescript/module/toast/animations.d.ts +62 -0
- package/lib/typescript/module/toast/animations.d.ts.map +1 -0
- package/lib/typescript/module/toast/constants.d.ts +39 -0
- package/lib/typescript/module/toast/constants.d.ts.map +1 -0
- package/lib/typescript/module/toast/context.d.ts +19 -0
- package/lib/typescript/module/toast/context.d.ts.map +1 -0
- package/lib/typescript/module/toast/index.d.ts +23 -76
- package/lib/typescript/module/toast/index.d.ts.map +1 -1
- package/lib/typescript/module/toast/position-utils.d.ts +30 -0
- package/lib/typescript/module/toast/position-utils.d.ts.map +1 -0
- package/lib/typescript/module/toast/positioner-utils.d.ts +72 -0
- package/lib/typescript/module/toast/positioner-utils.d.ts.map +1 -0
- package/lib/typescript/module/toast/toast-comparator.d.ts +12 -0
- package/lib/typescript/module/toast/toast-comparator.d.ts.map +1 -0
- package/lib/typescript/module/toast/toast-fns.d.ts +3 -0
- package/lib/typescript/module/toast/toast-fns.d.ts.map +1 -0
- package/lib/typescript/module/toast/toast-store.d.ts +52 -0
- package/lib/typescript/module/toast/toast-store.d.ts.map +1 -0
- package/lib/typescript/module/toast/toast-timers.d.ts +24 -0
- package/lib/typescript/module/toast/toast-timers.d.ts.map +1 -0
- package/lib/typescript/module/toast/types.d.ts +222 -5
- package/lib/typescript/module/toast/types.d.ts.map +1 -1
- package/lib/typescript/module/toast/use-animated-target.d.ts +7 -0
- package/lib/typescript/module/toast/use-animated-target.d.ts.map +1 -0
- package/lib/typescript/module/toast/use-app-state.d.ts +18 -0
- package/lib/typescript/module/toast/use-app-state.d.ts.map +1 -0
- package/lib/typescript/module/toast/use-toast-colors.d.ts +22 -0
- package/lib/typescript/module/toast/use-toast-colors.d.ts.map +1 -0
- package/lib/typescript/module/toast/use-toast-position.d.ts +37 -0
- package/lib/typescript/module/toast/use-toast-position.d.ts.map +1 -0
- package/lib/typescript/module/tooltip/index.web.d.ts.map +1 -1
- package/lib/typescript/module/zoomable-image-gallery/ZoomableImageGallery.d.ts.map +1 -1
- package/package.json +58 -26
- package/src/__tests__/TabBar.test.tsx +342 -0
- package/src/__tests__/TabBarGlassFallback.test.tsx +234 -0
- package/src/__tests__/TabBarReanimatedDeps.test.ts +130 -0
- package/src/__tests__/TabBarWebFork.test.ts +243 -0
- package/src/__tests__/ToastContent.test.tsx +192 -0
- package/src/__tests__/ToastHostWebFork.test.ts +155 -0
- package/src/__tests__/Toaster.test.tsx +527 -0
- package/src/__tests__/animated-style-deps.test.ts +156 -0
- package/src/__tests__/icon-references.test.ts +243 -0
- package/src/__tests__/toast-animations.test.ts +98 -0
- package/src/__tests__/toast-comparator.test.ts +131 -0
- package/src/__tests__/toast-enter-driver.test.ts +147 -0
- package/src/__tests__/toast-fns.test.ts +240 -0
- package/src/__tests__/toast-position-utils.test.ts +259 -0
- package/src/__tests__/toast-positioner-utils.test.ts +214 -0
- package/src/__tests__/toast-store.test.ts +622 -0
- package/src/__tests__/toast-timers.test.ts +163 -0
- package/src/__tests__/use-animated-target.test.tsx +60 -0
- package/src/__tests__/use-app-state.test.tsx +127 -0
- package/src/__tests__/use-toast-colors.test.tsx +189 -0
- package/src/__tests__/web-position-fixed.test.ts +70 -0
- package/src/avatar-group/AvatarGroup.web.tsx +2 -1
- package/src/benefit-list/types.ts +2 -1
- package/src/bottom-sheet/index.web.tsx +3 -2
- package/src/context-menu/index.web.tsx +3 -2
- package/src/dialog/Dialog.web.tsx +4 -3
- package/src/fab/types.ts +4 -2
- package/src/frosted-icon-button/shared.ts +1 -1
- package/src/frosted-icon-button/types.ts +2 -1
- package/src/index.ts +4 -1
- package/src/index.web.ts +4 -1
- package/src/menu/index.web.tsx +2 -1
- package/src/popover/index.web.tsx +3 -2
- package/src/portal/index.tsx +4 -1
- package/src/progressive-blur/index.tsx +78 -0
- package/src/progressive-blur/index.web.tsx +65 -0
- package/src/progressive-blur/shared.ts +81 -0
- package/src/progressive-blur/types.ts +21 -0
- package/src/select/index.web.tsx +2 -1
- package/src/styles/web-view-style.ts +21 -0
- package/src/tab-bar/TabBar.stories.tsx +217 -0
- package/src/tab-bar/TabBarBase.tsx +517 -0
- package/src/tab-bar/expo-router/RouterTabBar.tsx +80 -0
- package/src/tab-bar/expo-router/fading-tab-screen.tsx +109 -0
- package/src/tab-bar/expo-router/index.ts +13 -0
- package/src/tab-bar/glyph.native.tsx +46 -0
- package/src/tab-bar/glyph.tsx +31 -0
- package/src/tab-bar/index.ts +32 -0
- package/src/tab-bar/index.web.tsx +34 -0
- package/src/tab-bar/minimize-context.tsx +117 -0
- package/src/tab-bar/shared.ts +159 -0
- package/src/tab-bar/surface-solid.tsx +40 -0
- package/src/tab-bar/surface.native.tsx +122 -0
- package/src/tab-bar/surface.tsx +28 -0
- package/src/tab-bar/surface.web.tsx +56 -0
- package/src/tab-bar/types.ts +91 -0
- package/src/toast/Positioner.tsx +121 -0
- package/src/toast/Toast.stories.tsx +292 -65
- package/src/toast/ToastContent.tsx +405 -0
- package/src/toast/ToastHost.native.tsx +31 -0
- package/src/toast/ToastHost.tsx +67 -0
- package/src/toast/ToastIcon.tsx +55 -0
- package/src/toast/ToastRow.tsx +485 -0
- package/src/toast/ToastSwipeHandler.tsx +222 -0
- package/src/toast/Toaster.tsx +259 -0
- package/src/toast/animations.ts +313 -0
- package/src/toast/constants.ts +76 -0
- package/src/toast/context.tsx +44 -0
- package/src/toast/index.tsx +47 -123
- package/src/toast/position-utils.ts +149 -0
- package/src/toast/positioner-utils.ts +142 -0
- package/src/toast/toast-comparator.ts +41 -0
- package/src/toast/toast-fns.ts +104 -0
- package/src/toast/toast-store.ts +432 -0
- package/src/toast/toast-timers.ts +124 -0
- package/src/toast/types.ts +301 -5
- package/src/toast/use-animated-target.ts +61 -0
- package/src/toast/use-app-state.ts +77 -0
- package/src/toast/use-toast-colors.ts +133 -0
- package/src/toast/use-toast-position.ts +46 -0
- package/src/tooltip/index.web.tsx +2 -1
- package/src/zoomable-image-gallery/ZoomableImageGallery.stories.tsx +134 -0
- package/src/zoomable-image-gallery/ZoomableImageGallery.tsx +50 -27
- package/lib/commonjs/toast/Toast.js +0 -267
- package/lib/commonjs/toast/Toast.js.map +0 -1
- package/lib/commonjs/toast/const.js +0 -8
- package/lib/commonjs/toast/const.js.map +0 -1
- package/lib/commonjs/toast/index.web.js +0 -114
- package/lib/commonjs/toast/index.web.js.map +0 -1
- package/lib/commonjs/toast/sonner/index.js +0 -9
- package/lib/commonjs/toast/sonner/index.js.map +0 -1
- package/lib/commonjs/toast/sonner/index.web.js +0 -9
- package/lib/commonjs/toast/sonner/index.web.js.map +0 -1
- package/lib/module/toast/Toast.js +0 -258
- package/lib/module/toast/Toast.js.map +0 -1
- package/lib/module/toast/const.js +0 -4
- package/lib/module/toast/const.js.map +0 -1
- package/lib/module/toast/index.web.js +0 -74
- package/lib/module/toast/index.web.js.map +0 -1
- package/lib/module/toast/sonner/index.js +0 -5
- package/lib/module/toast/sonner/index.js.map +0 -1
- package/lib/module/toast/sonner/index.web.js +0 -5
- package/lib/module/toast/sonner/index.web.js.map +0 -1
- package/lib/typescript/commonjs/toast/Toast.d.ts +0 -23
- package/lib/typescript/commonjs/toast/Toast.d.ts.map +0 -1
- package/lib/typescript/commonjs/toast/const.d.ts +0 -2
- package/lib/typescript/commonjs/toast/const.d.ts.map +0 -1
- package/lib/typescript/commonjs/toast/index.web.d.ts +0 -29
- package/lib/typescript/commonjs/toast/index.web.d.ts.map +0 -1
- package/lib/typescript/commonjs/toast/sonner/index.d.ts +0 -2
- package/lib/typescript/commonjs/toast/sonner/index.d.ts.map +0 -1
- package/lib/typescript/commonjs/toast/sonner/index.web.d.ts +0 -2
- package/lib/typescript/commonjs/toast/sonner/index.web.d.ts.map +0 -1
- package/lib/typescript/module/toast/Toast.d.ts +0 -23
- package/lib/typescript/module/toast/Toast.d.ts.map +0 -1
- package/lib/typescript/module/toast/const.d.ts +0 -2
- package/lib/typescript/module/toast/const.d.ts.map +0 -1
- package/lib/typescript/module/toast/index.web.d.ts +0 -29
- package/lib/typescript/module/toast/index.web.d.ts.map +0 -1
- package/lib/typescript/module/toast/sonner/index.d.ts +0 -2
- package/lib/typescript/module/toast/sonner/index.d.ts.map +0 -1
- package/lib/typescript/module/toast/sonner/index.web.d.ts +0 -2
- package/lib/typescript/module/toast/sonner/index.web.d.ts.map +0 -1
- package/src/toast/Toast.tsx +0 -269
- package/src/toast/const.ts +0 -1
- package/src/toast/index.web.tsx +0 -101
- package/src/toast/sonner/index.ts +0 -3
- package/src/toast/sonner/index.web.ts +0 -3
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { ReactTestInstance } from 'react-test-renderer';
|
|
3
|
+
import { render } from '@testing-library/react-native';
|
|
4
|
+
|
|
5
|
+
import type { TabBarSurfaceProps } from '../tab-bar/shared';
|
|
6
|
+
import type { TabBarTheme } from '../tab-bar/types';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The native capsule surface must DEGRADE, never crash, when `expo-glass-effect`
|
|
10
|
+
* is not really usable.
|
|
11
|
+
*
|
|
12
|
+
* This is the one thing the rest of the tab-bar suite structurally cannot see.
|
|
13
|
+
* `TabBar.test.tsx` renders the native surface against the manual mock in
|
|
14
|
+
* `__mocks__/expo-glass-effect.ts`, which is a HEALTHY install reporting
|
|
15
|
+
* `isLiquidGlassAvailable() === false` — so it only ever exercises the branch a
|
|
16
|
+
* correctly-packaged Android device takes. Every failure mode below is a
|
|
17
|
+
* different install: the module resolved but handed back no exports, or the JS
|
|
18
|
+
* package is there while the native module is not.
|
|
19
|
+
*
|
|
20
|
+
* Each case is re-mocked into its own module registry because both hazards live at
|
|
21
|
+
* MODULE scope. `Animated.createAnimatedComponent(GlassView)` runs on import, and
|
|
22
|
+
* on iOS `isLiquidGlassAvailable()` reaches a native module through
|
|
23
|
+
* `requireNativeModule`, which throws by contract when it is absent. Mocking after
|
|
24
|
+
* the module under test was imported would test a render branch and miss both.
|
|
25
|
+
*
|
|
26
|
+
* The two counter-tests at the end are what keep the rest honest: a guard that
|
|
27
|
+
* always fell through to the solid surface would satisfy every other assertion
|
|
28
|
+
* here while silently deleting the glass look on every iOS 26 device.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/** Every export may be absent — that is the whole point of these fixtures. */
|
|
32
|
+
interface GlassEffectModule {
|
|
33
|
+
GlassView?: unknown;
|
|
34
|
+
isLiquidGlassAvailable?: () => boolean;
|
|
35
|
+
isGlassEffectAPIAvailable?: () => boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* A host tag stands in for the real `GlassView` component: under the reanimated
|
|
40
|
+
* mock `createAnimatedComponent` is the identity, so whatever the package exports
|
|
41
|
+
* IS the element type, and a string host is the cheapest valid one to assert on.
|
|
42
|
+
* It matches the tag the manual mock renders.
|
|
43
|
+
*/
|
|
44
|
+
const GLASS_HOST = 'GlassView';
|
|
45
|
+
|
|
46
|
+
const THEME: TabBarTheme = {
|
|
47
|
+
activeTint: 'rgb(20 20 20)',
|
|
48
|
+
inactiveTint: 'rgb(120 120 120)',
|
|
49
|
+
highlight: 'rgb(230 230 230)',
|
|
50
|
+
glassTint: 'rgba(255, 255, 255, 0.55)',
|
|
51
|
+
solidFallback: 'rgb(246 246 246)',
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const STYLE = { borderRadius: 29 };
|
|
55
|
+
|
|
56
|
+
function flattenStyle(style: unknown): Record<string, unknown> {
|
|
57
|
+
const out: Record<string, unknown> = {};
|
|
58
|
+
const visit = (s: unknown): void => {
|
|
59
|
+
if (Array.isArray(s)) s.forEach(visit);
|
|
60
|
+
else if (s && typeof s === 'object') Object.assign(out, s);
|
|
61
|
+
};
|
|
62
|
+
visit(style);
|
|
63
|
+
return out;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Every host node rendered as `tag`. */
|
|
67
|
+
function hosts(root: ReactTestInstance, tag: string): ReactTestInstance[] {
|
|
68
|
+
return root.findAll((node) => typeof node.type === 'string' && node.type === tag);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Render `surface.native.tsx` against a given `expo-glass-effect`.
|
|
73
|
+
*
|
|
74
|
+
* Only the surface comes from the isolated registry — testing-library registers
|
|
75
|
+
* suite-level hooks when it loads, so it has to be imported at the top of the file
|
|
76
|
+
* rather than inside a test. Nothing in the rendered tree calls a hook, and the
|
|
77
|
+
* surface renders host strings from the reanimated mock, so the two registries
|
|
78
|
+
* never have to agree on a React instance. `times` re-renders within one registry,
|
|
79
|
+
* for the assertion about module-scoped memoization.
|
|
80
|
+
*/
|
|
81
|
+
function renderNativeSurface(glassEffect: GlassEffectModule, times = 1): ReactTestInstance {
|
|
82
|
+
let root: ReactTestInstance | undefined;
|
|
83
|
+
|
|
84
|
+
jest.isolateModules(() => {
|
|
85
|
+
jest.doMock('expo-glass-effect', () => glassEffect);
|
|
86
|
+
|
|
87
|
+
const { TabBarSurface } = require('../tab-bar/surface.native') as {
|
|
88
|
+
TabBarSurface: React.ComponentType<TabBarSurfaceProps>;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
for (let i = 0; i < times; i += 1) {
|
|
92
|
+
root = render(<TabBarSurface theme={THEME} style={STYLE} />).UNSAFE_root;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
if (!root) throw new Error('the native surface did not render');
|
|
97
|
+
return root;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Assert the tree is the opaque non-glass surface, filled from the theme. */
|
|
101
|
+
function expectSolidFallback(root: ReactTestInstance): void {
|
|
102
|
+
expect(hosts(root, GLASS_HOST)).toHaveLength(0);
|
|
103
|
+
const surface = hosts(root, 'Animated.View')[0];
|
|
104
|
+
expect(surface).toBeTruthy();
|
|
105
|
+
expect(flattenStyle(surface?.props.style).backgroundColor).toBe(THEME.solidFallback);
|
|
106
|
+
// The animated capsule radius must survive the fallback — the pill still
|
|
107
|
+
// reshapes as the bar minimizes.
|
|
108
|
+
expect(flattenStyle(surface?.props.style).borderRadius).toBe(STYLE.borderRadius);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
describe('TabBarSurface (native) — degrading when glass is unusable', () => {
|
|
112
|
+
let warn: jest.SpyInstance<void, Parameters<typeof console.warn>>;
|
|
113
|
+
|
|
114
|
+
beforeEach(() => {
|
|
115
|
+
jest.resetModules();
|
|
116
|
+
warn = jest.spyOn(console, 'warn').mockImplementation(() => undefined);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
afterEach(() => {
|
|
120
|
+
warn.mockRestore();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('falls back when the module resolved without GlassView', () => {
|
|
124
|
+
// `createAnimatedComponent(undefined)` produces an element type React rejects
|
|
125
|
+
// with "Element type is invalid … but got: undefined" — and it happens at
|
|
126
|
+
// import, so the whole screen the bar is on goes down with it.
|
|
127
|
+
expectSolidFallback(
|
|
128
|
+
renderNativeSurface({ GlassView: undefined, isLiquidGlassAvailable: () => true }),
|
|
129
|
+
);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('falls back when the module delivered no exports at all', () => {
|
|
133
|
+
// A stub, an alias, or a resolver that landed on a platform-specific file:
|
|
134
|
+
// there is no `isLiquidGlassAvailable` to call either, so calling it blindly
|
|
135
|
+
// is a TypeError.
|
|
136
|
+
expectSolidFallback(renderNativeSurface({}));
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('falls back when the native module is missing from the build', () => {
|
|
140
|
+
// On iOS `isLiquidGlassAvailable()` resolves `ExpoGlassEffect` through
|
|
141
|
+
// `requireNativeModule`, which THROWS by contract when the module is not in
|
|
142
|
+
// the binary — an OTA JS update landing on a binary built before the package
|
|
143
|
+
// was linked reaches exactly this state.
|
|
144
|
+
expectSolidFallback(
|
|
145
|
+
renderNativeSurface({
|
|
146
|
+
GlassView: GLASS_HOST,
|
|
147
|
+
isLiquidGlassAvailable: () => {
|
|
148
|
+
throw new Error("Cannot find native module 'ExpoGlassEffect'");
|
|
149
|
+
},
|
|
150
|
+
}),
|
|
151
|
+
);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('reports the missing native module instead of swallowing it', () => {
|
|
155
|
+
renderNativeSurface({
|
|
156
|
+
GlassView: GLASS_HOST,
|
|
157
|
+
isLiquidGlassAvailable: () => {
|
|
158
|
+
throw new Error("Cannot find native module 'ExpoGlassEffect'");
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
expect(warn).toHaveBeenCalledTimes(1);
|
|
163
|
+
const [message, detail] = warn.mock.calls[0] ?? [];
|
|
164
|
+
expect(String(message)).toContain('expo-glass-effect');
|
|
165
|
+
expect(String(detail)).toContain("Cannot find native module 'ExpoGlassEffect'");
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('falls back when the platform has no glass API (iOS 26 betas)', () => {
|
|
169
|
+
// Upstream's own guard: on those builds `isLiquidGlassAvailable()` answers
|
|
170
|
+
// true while touching `GlassView` crashes NATIVELY, below JS.
|
|
171
|
+
expectSolidFallback(
|
|
172
|
+
renderNativeSurface({
|
|
173
|
+
GlassView: GLASS_HOST,
|
|
174
|
+
isLiquidGlassAvailable: () => true,
|
|
175
|
+
isGlassEffectAPIAvailable: () => false,
|
|
176
|
+
}),
|
|
177
|
+
);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('renders real glass when the package is fully there', () => {
|
|
181
|
+
const root = renderNativeSurface({
|
|
182
|
+
GlassView: GLASS_HOST,
|
|
183
|
+
isLiquidGlassAvailable: () => true,
|
|
184
|
+
isGlassEffectAPIAvailable: () => true,
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
const glass = hosts(root, GLASS_HOST)[0];
|
|
188
|
+
expect(glass).toBeTruthy();
|
|
189
|
+
expect(glass?.props.glassEffectStyle).toBe('regular');
|
|
190
|
+
expect(flattenStyle(glass?.props.style).backgroundColor).toBe(THEME.glassTint);
|
|
191
|
+
expect(warn).not.toHaveBeenCalled();
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('renders glass on a version that predates isGlassEffectAPIAvailable', () => {
|
|
195
|
+
// The probe first shipped in 0.1.9, so the `>=0.1.9` peer floor guarantees it
|
|
196
|
+
// — but a peer range only WARNS, so a consumer can still resolve an older
|
|
197
|
+
// copy. A missing probe means "not applicable", never "unavailable"; treating
|
|
198
|
+
// it as the latter would delete the glass look on every working device.
|
|
199
|
+
expect(
|
|
200
|
+
hosts(
|
|
201
|
+
renderNativeSurface({ GlassView: GLASS_HOST, isLiquidGlassAvailable: () => true }),
|
|
202
|
+
GLASS_HOST,
|
|
203
|
+
),
|
|
204
|
+
).toHaveLength(1);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it('probes availability once per session, not once per render', () => {
|
|
208
|
+
let probes = 0;
|
|
209
|
+
renderNativeSurface(
|
|
210
|
+
{
|
|
211
|
+
GlassView: GLASS_HOST,
|
|
212
|
+
isLiquidGlassAvailable: () => {
|
|
213
|
+
probes += 1;
|
|
214
|
+
return true;
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
3,
|
|
218
|
+
);
|
|
219
|
+
expect(probes).toBe(1);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('reuses the neutral surface rather than a second implementation', () => {
|
|
223
|
+
// Two copies of the fallback would drift: the neutral variant is what web
|
|
224
|
+
// bundlers and a consumer's `tsc` resolve, and it must paint exactly what an
|
|
225
|
+
// Android device paints.
|
|
226
|
+
jest.isolateModules(() => {
|
|
227
|
+
const { TabBarSurface } = require('../tab-bar/surface') as { TabBarSurface: unknown };
|
|
228
|
+
const { SolidTabBarSurface } = require('../tab-bar/surface-solid') as {
|
|
229
|
+
SolidTabBarSurface: unknown;
|
|
230
|
+
};
|
|
231
|
+
expect(TabBarSurface).toBe(SolidTabBarSurface);
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
});
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { readdirSync, readFileSync, statSync } from 'node:fs';
|
|
2
|
+
import { join, relative } from 'node:path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Every reanimated mapper in the tab bar must pass a NON-EMPTY dependency array.
|
|
6
|
+
*
|
|
7
|
+
* On web WITHOUT the react-native-worklets babel plugin — the production reality
|
|
8
|
+
* for every Oxy RN-Web app — reanimated cannot auto-detect which shared values a
|
|
9
|
+
* worklet reads, so it drives the mapper off its deps array instead. A missing or
|
|
10
|
+
* empty array means the mapper runs ONCE and freezes at the first frame: the
|
|
11
|
+
* shared values keep animating underneath, the DOM never updates. For this
|
|
12
|
+
* component that means a bar that never minimizes, a highlight that never moves
|
|
13
|
+
* and a scroll handler bound to the first render's state — with no error
|
|
14
|
+
* anywhere. Native (plugin present) auto-tracks and ignores the extra deps, so
|
|
15
|
+
* listing them is correct on both platforms.
|
|
16
|
+
*
|
|
17
|
+
* This is deliberately STRICTER than the repo-wide `animated-style-deps` guard,
|
|
18
|
+
* which only checks that the values a mapper reads appear in the deps it
|
|
19
|
+
* declares. Here every mapper must carry a real deps array whether or not the
|
|
20
|
+
* regex can see a `.value` read inside it, and `useAnimatedScrollHandler` — which
|
|
21
|
+
* the repo-wide guard does not scan at all — is included, because
|
|
22
|
+
* `useMinimizeOnScroll` is the single entry point through which every screen
|
|
23
|
+
* drives the bar.
|
|
24
|
+
*
|
|
25
|
+
* Jest cannot catch this class at all: the reanimated mock resolves mappers
|
|
26
|
+
* synchronously, so a frozen mapper and a working one render identically. Source
|
|
27
|
+
* analysis is the only automatable check; the real behaviour is verified in a
|
|
28
|
+
* foregrounded browser tab.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
const SRC = join(__dirname, '..');
|
|
32
|
+
const ROOTS = ['tab-bar', 'progressive-blur'] as const;
|
|
33
|
+
const MAPPERS = [
|
|
34
|
+
'useAnimatedStyle',
|
|
35
|
+
'useAnimatedScrollHandler',
|
|
36
|
+
'useDerivedValue',
|
|
37
|
+
'useAnimatedProps',
|
|
38
|
+
] as const;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Floors for the self-check, not exact counts — a new mapper or module must not
|
|
42
|
+
* fail this suite, but a walk that silently stops finding things must.
|
|
43
|
+
*/
|
|
44
|
+
const MIN_FILES = 16;
|
|
45
|
+
const MIN_MAPPERS = 7;
|
|
46
|
+
|
|
47
|
+
type Offender = { location: string; mapper: string; problem: string };
|
|
48
|
+
|
|
49
|
+
/** Comments legitimately discuss mappers and show them in examples. */
|
|
50
|
+
function stripComments(source: string): string {
|
|
51
|
+
return source
|
|
52
|
+
.replace(/\/\*[\s\S]*?\*\//g, (block) => '\n'.repeat((block.match(/\n/g) ?? []).length))
|
|
53
|
+
.replace(/^[ \t]*\/\/.*$/gm, '');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function sourceFiles(dir: string): string[] {
|
|
57
|
+
return readdirSync(dir).flatMap((entry) => {
|
|
58
|
+
const full = join(dir, entry);
|
|
59
|
+
if (statSync(full).isDirectory()) {
|
|
60
|
+
return entry === '__tests__' ? [] : sourceFiles(full);
|
|
61
|
+
}
|
|
62
|
+
return /\.tsx?$/.test(entry) ? [full] : [];
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Text between the parens of the call starting at `start`, paren-balanced. */
|
|
67
|
+
function callText(source: string, start: number): string {
|
|
68
|
+
const open = source.indexOf('(', start);
|
|
69
|
+
let depth = 0;
|
|
70
|
+
for (let i = open; i < source.length; i++) {
|
|
71
|
+
if (source[i] === '(') depth += 1;
|
|
72
|
+
else if (source[i] === ')') {
|
|
73
|
+
depth -= 1;
|
|
74
|
+
if (depth === 0) return source.slice(open + 1, i);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return source.slice(open + 1);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function analyse(): { offenders: Offender[]; files: number; calls: number } {
|
|
81
|
+
const offenders: Offender[] = [];
|
|
82
|
+
const scanned = ROOTS.flatMap((root) => sourceFiles(join(SRC, root)));
|
|
83
|
+
let calls = 0;
|
|
84
|
+
|
|
85
|
+
for (const file of scanned) {
|
|
86
|
+
const source = stripComments(readFileSync(file, 'utf8'));
|
|
87
|
+
|
|
88
|
+
for (const mapper of MAPPERS) {
|
|
89
|
+
// `\b` before the name so `useAnimatedStyleX` can never match.
|
|
90
|
+
for (const call of source.matchAll(new RegExp(`\\b${mapper}\\s*\\(`, 'g'))) {
|
|
91
|
+
if (call.index === undefined) continue;
|
|
92
|
+
calls += 1;
|
|
93
|
+
|
|
94
|
+
const text = callText(source, call.index);
|
|
95
|
+
const line = source.slice(0, call.index).split('\n').length;
|
|
96
|
+
const location = `${relative(SRC, file)}:${line}`;
|
|
97
|
+
|
|
98
|
+
// Trailing comma after the deps array is idiomatic and must parse.
|
|
99
|
+
const deps = [...text.matchAll(/,\s*(\[[\s\S]*?\])\s*,?\s*$/g)].pop();
|
|
100
|
+
if (!deps) {
|
|
101
|
+
offenders.push({ location, mapper, problem: 'no deps array' });
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if ((deps[1] ?? '').replace(/\s/g, '') === '[]') {
|
|
105
|
+
offenders.push({ location, mapper, problem: 'empty deps array' });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return { offenders, files: scanned.length, calls };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const { offenders, files, calls } = analyse();
|
|
115
|
+
|
|
116
|
+
describe('tab-bar reanimated mapper dependency arrays', () => {
|
|
117
|
+
it('walked a plausible number of source files (guards against a broken walk)', () => {
|
|
118
|
+
expect(files).toBeGreaterThanOrEqual(MIN_FILES);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('found a plausible number of mapper call sites (guards against a vacuous pass)', () => {
|
|
122
|
+
// Without this, a broken regex would make the real assertion below pass by
|
|
123
|
+
// finding nothing at all.
|
|
124
|
+
expect(calls).toBeGreaterThanOrEqual(MIN_MAPPERS);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('has no mapper with a missing or empty deps array', () => {
|
|
128
|
+
expect(offenders.map((o) => `${o.location} ${o.mapper} — ${o.problem}`)).toEqual([]);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Structural guard for the tab bar's platform split.
|
|
6
|
+
*
|
|
7
|
+
* `@oxyhq/bloom/tab-bar` has to resolve cleanly in four places at once: Metro on
|
|
8
|
+
* iOS/Android (platform extensions), a web bundler (the `browser` export
|
|
9
|
+
* condition), a non-Metro bundler reading the published `lib/`, and a consumer's
|
|
10
|
+
* `tsc` (which follows the `"react-native"` source condition). Three packages
|
|
11
|
+
* break that the moment they appear outside a `.native` file:
|
|
12
|
+
* `expo-glass-effect` and `expo-symbols` are native-only, and `expo-router` /
|
|
13
|
+
* `react-native-screens` belong solely to the opt-in
|
|
14
|
+
* `@oxyhq/bloom/tab-bar/expo-router` subpath so the core bar stays usable in an
|
|
15
|
+
* app with no router at all.
|
|
16
|
+
*
|
|
17
|
+
* None of that is observable from a jest render — a missing `.web` retarget or a
|
|
18
|
+
* leaked native import fails at a consumer's BUILD, in a repo that isn't this
|
|
19
|
+
* one. Hence source/contract assertions.
|
|
20
|
+
*
|
|
21
|
+
* Every assertion below matches on real import/export/require STATEMENTS, never
|
|
22
|
+
* on bare substrings: the doc comments in these files name all four packages on
|
|
23
|
+
* purpose (explaining why they are absent), so `includes('expo-symbols')` would
|
|
24
|
+
* report a failure that is actually the documentation doing its job.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
const SRC = join(__dirname, '..');
|
|
28
|
+
const REPO_ROOT = join(SRC, '..');
|
|
29
|
+
|
|
30
|
+
const read = (rel: string) => readFileSync(join(SRC, rel), 'utf8');
|
|
31
|
+
|
|
32
|
+
/** Packages that must never be reached from a neutral or web module. */
|
|
33
|
+
const PLATFORM_ONLY = [
|
|
34
|
+
'expo-glass-effect',
|
|
35
|
+
'expo-symbols',
|
|
36
|
+
'expo-router',
|
|
37
|
+
'react-native-screens',
|
|
38
|
+
] as const;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Files resolved by a web bundler, a non-Metro bundler, or a consumer's `tsc`.
|
|
42
|
+
* `expo-router/index.ts` and its siblings are deliberately absent — that subpath
|
|
43
|
+
* is where the router packages are allowed to live.
|
|
44
|
+
*/
|
|
45
|
+
const NEUTRAL_AND_WEB_FILES = [
|
|
46
|
+
'tab-bar/index.ts',
|
|
47
|
+
'tab-bar/index.web.tsx',
|
|
48
|
+
'tab-bar/types.ts',
|
|
49
|
+
'tab-bar/shared.ts',
|
|
50
|
+
'tab-bar/TabBarBase.tsx',
|
|
51
|
+
'tab-bar/minimize-context.tsx',
|
|
52
|
+
'tab-bar/surface.tsx',
|
|
53
|
+
'tab-bar/surface-solid.tsx',
|
|
54
|
+
'tab-bar/surface.web.tsx',
|
|
55
|
+
'tab-bar/glyph.tsx',
|
|
56
|
+
'progressive-blur/index.web.tsx',
|
|
57
|
+
'progressive-blur/shared.ts',
|
|
58
|
+
'progressive-blur/types.ts',
|
|
59
|
+
] as const;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Blank out comments so a doc comment discussing a package is not mistaken for
|
|
63
|
+
* an import of it. Line comments are matched only when they START the line, so
|
|
64
|
+
* a `//` inside a string literal (a URL) survives untouched.
|
|
65
|
+
*/
|
|
66
|
+
function stripComments(source: string): string {
|
|
67
|
+
return source
|
|
68
|
+
.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
69
|
+
.replace(/^[ \t]*\/\/.*$/gm, '');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Every module specifier the file actually imports, re-exports or requires. */
|
|
73
|
+
function moduleSpecifiers(source: string): string[] {
|
|
74
|
+
const code = stripComments(source);
|
|
75
|
+
const patterns = [
|
|
76
|
+
/\bfrom\s*['"]([^'"]+)['"]/g, // import … from 'x' / export … from 'x'
|
|
77
|
+
/\bimport\s*['"]([^'"]+)['"]/g, // bare side-effect import 'x'
|
|
78
|
+
/\brequire\(\s*['"]([^'"]+)['"]\s*\)/g,
|
|
79
|
+
/\bimport\(\s*['"]([^'"]+)['"]\s*\)/g,
|
|
80
|
+
];
|
|
81
|
+
const found = new Set<string>();
|
|
82
|
+
for (const pattern of patterns) {
|
|
83
|
+
for (const match of code.matchAll(pattern)) {
|
|
84
|
+
if (match[1]) found.add(match[1]);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return [...found];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** True when `specifier` resolves to `pkg` (bare or a subpath of it). */
|
|
91
|
+
function isFrom(specifier: string, pkg: string): boolean {
|
|
92
|
+
return specifier === pkg || specifier.startsWith(`${pkg}/`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
describe('tab-bar platform split', () => {
|
|
96
|
+
it('the extractor sees real imports and ignores commented-out ones', () => {
|
|
97
|
+
// Self-check: if `moduleSpecifiers` breaks, every assertion below would
|
|
98
|
+
// pass vacuously by finding nothing.
|
|
99
|
+
const probe = [
|
|
100
|
+
"/* a doc comment naming expo-symbols and expo-router */",
|
|
101
|
+
"// import { Nope } from 'react-native-screens';",
|
|
102
|
+
"import { A } from 'react-native';",
|
|
103
|
+
"export type { B } from './types';",
|
|
104
|
+
"const c = require('expo-glass-effect');",
|
|
105
|
+
].join('\n');
|
|
106
|
+
expect(moduleSpecifiers(probe).sort()).toEqual([
|
|
107
|
+
'./types',
|
|
108
|
+
'expo-glass-effect',
|
|
109
|
+
'react-native',
|
|
110
|
+
]);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it.each(NEUTRAL_AND_WEB_FILES)('%s imports no native-only or router package', (file) => {
|
|
114
|
+
const specifiers = moduleSpecifiers(read(file));
|
|
115
|
+
const leaked = specifiers.filter((s) => PLATFORM_ONLY.some((pkg) => isFrom(s, pkg)));
|
|
116
|
+
expect(leaked).toEqual([]);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('the web progressive blur drops expo-blur for one masked backdrop-filter', () => {
|
|
120
|
+
// Ten stacked BlurViews would be ten composited backdrop passes per frame.
|
|
121
|
+
expect(moduleSpecifiers(read('progressive-blur/index.web.tsx'))).not.toContain('expo-blur');
|
|
122
|
+
expect(moduleSpecifiers(read('progressive-blur/index.tsx'))).toContain('expo-blur');
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('the native surface and glyph are the ONLY holders of the native packages', () => {
|
|
126
|
+
// The guard above only proves absence; this proves the split is real rather
|
|
127
|
+
// than the feature having quietly lost its native path.
|
|
128
|
+
expect(moduleSpecifiers(read('tab-bar/surface.native.tsx'))).toContain('expo-glass-effect');
|
|
129
|
+
expect(moduleSpecifiers(read('tab-bar/glyph.native.tsx'))).toContain('expo-symbols');
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('the native surface takes its fallback from surface-solid, never ./surface', () => {
|
|
133
|
+
// Metro resolves a bare `./surface` to `surface.native.tsx` from ANY caller,
|
|
134
|
+
// so importing the neutral sibling by that name would be a self-import — which
|
|
135
|
+
// is the entire reason `surface-solid.tsx` exists as a separate name.
|
|
136
|
+
const specifiers = moduleSpecifiers(read('tab-bar/surface.native.tsx'));
|
|
137
|
+
expect(specifiers).toContain('./surface-solid');
|
|
138
|
+
expect(specifiers).not.toContain('./surface');
|
|
139
|
+
// And the neutral variant must be that same component, not a second copy.
|
|
140
|
+
expect(moduleSpecifiers(read('tab-bar/surface.tsx'))).toContain('./surface-solid');
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('the router packages live only under tab-bar/expo-router', () => {
|
|
144
|
+
const router = moduleSpecifiers(read('tab-bar/expo-router/RouterTabBar.tsx'));
|
|
145
|
+
expect(router.some((s) => isFrom(s, 'expo-router'))).toBe(true);
|
|
146
|
+
const screen = moduleSpecifiers(read('tab-bar/expo-router/fading-tab-screen.tsx'));
|
|
147
|
+
expect(screen).toContain('react-native-screens');
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('the default entry imports the platform pieces BY BARE NAME (Metro picks .native)', () => {
|
|
151
|
+
const specifiers = moduleSpecifiers(read('tab-bar/index.ts'));
|
|
152
|
+
expect(specifiers).toContain('./surface');
|
|
153
|
+
expect(specifiers).toContain('./glyph');
|
|
154
|
+
expect(specifiers).toContain('../progressive-blur');
|
|
155
|
+
// A `.web` path here would pin every platform to the web fork.
|
|
156
|
+
expect(specifiers).not.toContain('./surface.web');
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('the web entry imports the web pieces by their FULL .web name', () => {
|
|
160
|
+
// Inside the published `lib/` every file is plain `.js`, and no web bundler
|
|
161
|
+
// resolves a bare `./surface` to the `.web` sibling — only Metro does.
|
|
162
|
+
const specifiers = moduleSpecifiers(read('tab-bar/index.web.tsx'));
|
|
163
|
+
expect(specifiers).toContain('./surface.web');
|
|
164
|
+
expect(specifiers).toContain('../progressive-blur/index.web');
|
|
165
|
+
expect(specifiers).not.toContain('./surface');
|
|
166
|
+
// `./glyph` has no web fork: the neutral file already renders `item.icon`,
|
|
167
|
+
// which is the correct web behaviour.
|
|
168
|
+
expect(specifiers).toContain('./glyph');
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
describe('tab-bar published surface', () => {
|
|
173
|
+
const pkg = JSON.parse(readFileSync(join(REPO_ROOT, 'package.json'), 'utf8')) as {
|
|
174
|
+
exports: Record<string, { browser?: { import?: string; require?: string } }>;
|
|
175
|
+
peerDependencies: Record<string, string>;
|
|
176
|
+
peerDependenciesMeta: Record<string, { optional?: boolean }>;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
it('exports ./tab-bar with a browser condition → index.web.js', () => {
|
|
180
|
+
const entry = pkg.exports['./tab-bar'];
|
|
181
|
+
expect(entry).toBeDefined();
|
|
182
|
+
expect(entry?.browser?.import).toBe('./lib/module/tab-bar/index.web.js');
|
|
183
|
+
expect(entry?.browser?.require).toBe('./lib/commonjs/tab-bar/index.web.js');
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it('exports ./progressive-blur with a browser condition → index.web.js', () => {
|
|
187
|
+
expect(pkg.exports['./progressive-blur']?.browser?.import).toBe(
|
|
188
|
+
'./lib/module/progressive-blur/index.web.js',
|
|
189
|
+
);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it('exports ./tab-bar/expo-router with NO browser condition', () => {
|
|
193
|
+
// The router adapter is universal — it only re-binds `TabBar`/`TabBarButton`,
|
|
194
|
+
// whose own entry already resolves per platform. There is no `.web` sibling,
|
|
195
|
+
// so a browser condition would point at a file bob never emits.
|
|
196
|
+
const entry = pkg.exports['./tab-bar/expo-router'];
|
|
197
|
+
expect(entry).toBeDefined();
|
|
198
|
+
expect(entry?.browser).toBeUndefined();
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('declares the two Apple-only native peers REQUIRED, keeping their ranges', () => {
|
|
202
|
+
// `expo-glass-effect` and `expo-symbols` are imported STATICALLY, by
|
|
203
|
+
// `tab-bar/surface.native` and `tab-bar/glyph.native`. That is what settles
|
|
204
|
+
// this: optional means "you may omit this", but omitting it does not degrade
|
|
205
|
+
// — the native bundle fails to RESOLVE the specifier and the build dies. An
|
|
206
|
+
// optional peer plus a static import is an incoherent pair, and the only
|
|
207
|
+
// thing marking them optional would achieve is silencing the one warning
|
|
208
|
+
// that tells a consumer their build is about to break. Declared the same way
|
|
209
|
+
// `expo-blur` already is, for the same reason.
|
|
210
|
+
//
|
|
211
|
+
// The RANGE carries the second half: both files import symbols that arrived
|
|
212
|
+
// after 1.0 — `isGlassEffectAPIAvailable` first shipped in
|
|
213
|
+
// expo-glass-effect 0.1.9 — so an older installed copy is a real
|
|
214
|
+
// incompatibility, not merely an absent one.
|
|
215
|
+
for (const peer of ['expo-glass-effect', 'expo-symbols']) {
|
|
216
|
+
expect(pkg.peerDependencies[peer]).toMatch(/^>=\d/);
|
|
217
|
+
expect(pkg.peerDependenciesMeta[peer]).toBeUndefined();
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('keeps the cross-platform native peers REQUIRED', () => {
|
|
222
|
+
// `expo-blur` and `expo-image` are apple+android native modules imported from
|
|
223
|
+
// platform-NEUTRAL files (`progressive-blur/index.tsx`,
|
|
224
|
+
// `frosted-icon-button/FrostedIconButton.tsx`, `zoomable-image-gallery/`), so
|
|
225
|
+
// every native platform genuinely needs them. Marking them optional would
|
|
226
|
+
// silence the one warning that tells a consumer their build is about to fail.
|
|
227
|
+
for (const peer of ['expo-blur', 'expo-image']) {
|
|
228
|
+
expect(pkg.peerDependencies[peer]).toBeDefined();
|
|
229
|
+
expect(pkg.peerDependenciesMeta[peer]).toBeUndefined();
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('the generator lists exactly the right subpaths as web-forked', () => {
|
|
234
|
+
const gen = readFileSync(join(REPO_ROOT, 'scripts/generate-platform-exports.mjs'), 'utf8');
|
|
235
|
+
const block = /const WEB_FORKED_SUBPATHS = new Set\(\[([\s\S]*?)\]\);/.exec(gen)?.[1];
|
|
236
|
+
expect(block).toBeDefined();
|
|
237
|
+
const listed = [...(block ?? '').matchAll(/^\s*'([^']+)',/gm)].map((m) => m[1]);
|
|
238
|
+
expect(listed).toContain('./tab-bar');
|
|
239
|
+
expect(listed).toContain('./progressive-blur');
|
|
240
|
+
// `assertWebSourceExists()` throws for this one — it has no `.web` sibling.
|
|
241
|
+
expect(listed).not.toContain('./tab-bar/expo-router');
|
|
242
|
+
});
|
|
243
|
+
});
|