@oxyhq/bloom 0.50.1 → 0.51.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +5 -3
- package/lib/commonjs/bottom-sheet/index.web.js.map +1 -1
- package/lib/commonjs/context-menu/index.web.js +6 -9
- package/lib/commonjs/context-menu/index.web.js.map +1 -1
- package/lib/commonjs/dialog/Dialog.js +12 -7
- package/lib/commonjs/dialog/Dialog.js.map +1 -1
- package/lib/commonjs/dialog/Dialog.web.js +18 -22
- package/lib/commonjs/dialog/Dialog.web.js.map +1 -1
- package/lib/commonjs/dialog/DialogHeader.js +61 -12
- package/lib/commonjs/dialog/DialogHeader.js.map +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 +5 -8
- package/lib/commonjs/menu/index.web.js.map +1 -1
- package/lib/commonjs/popover/index.web.js +8 -9
- 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 +5 -8
- package/lib/commonjs/select/index.web.js.map +1 -1
- package/lib/commonjs/slider/Slider.js +4 -9
- package/lib/commonjs/slider/Slider.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/switch/Switch.js +4 -8
- package/lib/commonjs/switch/Switch.js.map +1 -1
- 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.js +50 -0
- package/lib/commonjs/tab-bar/surface.js.map +1 -0
- package/lib/commonjs/tab-bar/surface.native.js +56 -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/tabs/Tabs.js +3 -8
- package/lib/commonjs/tabs/Tabs.js.map +1 -1
- 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 +5 -3
- package/lib/module/bottom-sheet/index.web.js.map +1 -1
- package/lib/module/context-menu/index.web.js +6 -9
- package/lib/module/context-menu/index.web.js.map +1 -1
- package/lib/module/dialog/Dialog.js +12 -7
- package/lib/module/dialog/Dialog.js.map +1 -1
- package/lib/module/dialog/Dialog.web.js +18 -22
- package/lib/module/dialog/Dialog.web.js.map +1 -1
- package/lib/module/dialog/DialogHeader.js +61 -12
- package/lib/module/dialog/DialogHeader.js.map +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 +5 -8
- package/lib/module/menu/index.web.js.map +1 -1
- package/lib/module/popover/index.web.js +8 -9
- 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 +5 -8
- package/lib/module/select/index.web.js.map +1 -1
- package/lib/module/slider/Slider.js +4 -9
- package/lib/module/slider/Slider.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/switch/Switch.js +4 -8
- package/lib/module/switch/Switch.js.map +1 -1
- 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.js +44 -0
- package/lib/module/tab-bar/surface.js.map +1 -0
- package/lib/module/tab-bar/surface.native.js +50 -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/tabs/Tabs.js +3 -8
- package/lib/module/tabs/Tabs.js.map +1 -1
- 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/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.d.ts.map +1 -1
- package/lib/typescript/commonjs/dialog/Dialog.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/dialog/DialogHeader.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/slider/Slider.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/switch/Switch.d.ts.map +1 -1
- 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.d.ts +6 -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 +85 -0
- package/lib/typescript/commonjs/tab-bar/types.d.ts.map +1 -0
- package/lib/typescript/commonjs/tabs/Tabs.d.ts.map +1 -1
- 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/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.d.ts.map +1 -1
- package/lib/typescript/module/dialog/Dialog.web.d.ts.map +1 -1
- package/lib/typescript/module/dialog/DialogHeader.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/slider/Slider.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/switch/Switch.d.ts.map +1 -1
- 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.d.ts +6 -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 +85 -0
- package/lib/typescript/module/tab-bar/types.d.ts.map +1 -0
- package/lib/typescript/module/tabs/Tabs.d.ts.map +1 -1
- 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 +63 -25
- package/src/__tests__/TabBar.test.tsx +342 -0
- package/src/__tests__/TabBarReanimatedDeps.test.ts +130 -0
- package/src/__tests__/TabBarWebFork.test.ts +197 -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__/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/bottom-sheet/index.web.tsx +4 -3
- package/src/context-menu/index.web.tsx +6 -6
- package/src/dialog/Dialog.tsx +7 -4
- package/src/dialog/Dialog.web.tsx +14 -14
- package/src/dialog/DialogHeader.tsx +72 -17
- package/src/index.ts +4 -1
- package/src/index.web.ts +4 -1
- package/src/menu/index.web.tsx +5 -5
- package/src/popover/index.web.tsx +8 -6
- 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 +5 -5
- package/src/slider/Slider.tsx +3 -5
- package/src/styles/web-view-style.ts +21 -0
- package/src/switch/Switch.tsx +4 -5
- 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.native.tsx +60 -0
- package/src/tab-bar/surface.tsx +47 -0
- package/src/tab-bar/surface.web.tsx +56 -0
- package/src/tab-bar/types.ts +88 -0
- package/src/tabs/Tabs.tsx +3 -5
- 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 -272
- 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 -263
- 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 -271
- 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,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,197 @@
|
|
|
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.web.tsx',
|
|
54
|
+
'tab-bar/glyph.tsx',
|
|
55
|
+
'progressive-blur/index.web.tsx',
|
|
56
|
+
'progressive-blur/shared.ts',
|
|
57
|
+
'progressive-blur/types.ts',
|
|
58
|
+
] as const;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Blank out comments so a doc comment discussing a package is not mistaken for
|
|
62
|
+
* an import of it. Line comments are matched only when they START the line, so
|
|
63
|
+
* a `//` inside a string literal (a URL) survives untouched.
|
|
64
|
+
*/
|
|
65
|
+
function stripComments(source: string): string {
|
|
66
|
+
return source
|
|
67
|
+
.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
68
|
+
.replace(/^[ \t]*\/\/.*$/gm, '');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Every module specifier the file actually imports, re-exports or requires. */
|
|
72
|
+
function moduleSpecifiers(source: string): string[] {
|
|
73
|
+
const code = stripComments(source);
|
|
74
|
+
const patterns = [
|
|
75
|
+
/\bfrom\s*['"]([^'"]+)['"]/g, // import … from 'x' / export … from 'x'
|
|
76
|
+
/\bimport\s*['"]([^'"]+)['"]/g, // bare side-effect import 'x'
|
|
77
|
+
/\brequire\(\s*['"]([^'"]+)['"]\s*\)/g,
|
|
78
|
+
/\bimport\(\s*['"]([^'"]+)['"]\s*\)/g,
|
|
79
|
+
];
|
|
80
|
+
const found = new Set<string>();
|
|
81
|
+
for (const pattern of patterns) {
|
|
82
|
+
for (const match of code.matchAll(pattern)) {
|
|
83
|
+
if (match[1]) found.add(match[1]);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return [...found];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** True when `specifier` resolves to `pkg` (bare or a subpath of it). */
|
|
90
|
+
function isFrom(specifier: string, pkg: string): boolean {
|
|
91
|
+
return specifier === pkg || specifier.startsWith(`${pkg}/`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
describe('tab-bar platform split', () => {
|
|
95
|
+
it('the extractor sees real imports and ignores commented-out ones', () => {
|
|
96
|
+
// Self-check: if `moduleSpecifiers` breaks, every assertion below would
|
|
97
|
+
// pass vacuously by finding nothing.
|
|
98
|
+
const probe = [
|
|
99
|
+
"/* a doc comment naming expo-symbols and expo-router */",
|
|
100
|
+
"// import { Nope } from 'react-native-screens';",
|
|
101
|
+
"import { A } from 'react-native';",
|
|
102
|
+
"export type { B } from './types';",
|
|
103
|
+
"const c = require('expo-glass-effect');",
|
|
104
|
+
].join('\n');
|
|
105
|
+
expect(moduleSpecifiers(probe).sort()).toEqual([
|
|
106
|
+
'./types',
|
|
107
|
+
'expo-glass-effect',
|
|
108
|
+
'react-native',
|
|
109
|
+
]);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it.each(NEUTRAL_AND_WEB_FILES)('%s imports no native-only or router package', (file) => {
|
|
113
|
+
const specifiers = moduleSpecifiers(read(file));
|
|
114
|
+
const leaked = specifiers.filter((s) => PLATFORM_ONLY.some((pkg) => isFrom(s, pkg)));
|
|
115
|
+
expect(leaked).toEqual([]);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('the web progressive blur drops expo-blur for one masked backdrop-filter', () => {
|
|
119
|
+
// Ten stacked BlurViews would be ten composited backdrop passes per frame.
|
|
120
|
+
expect(moduleSpecifiers(read('progressive-blur/index.web.tsx'))).not.toContain('expo-blur');
|
|
121
|
+
expect(moduleSpecifiers(read('progressive-blur/index.tsx'))).toContain('expo-blur');
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('the native surface and glyph are the ONLY holders of the native packages', () => {
|
|
125
|
+
// The guard above only proves absence; this proves the split is real rather
|
|
126
|
+
// than the feature having quietly lost its native path.
|
|
127
|
+
expect(moduleSpecifiers(read('tab-bar/surface.native.tsx'))).toContain('expo-glass-effect');
|
|
128
|
+
expect(moduleSpecifiers(read('tab-bar/glyph.native.tsx'))).toContain('expo-symbols');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('the router packages live only under tab-bar/expo-router', () => {
|
|
132
|
+
const router = moduleSpecifiers(read('tab-bar/expo-router/RouterTabBar.tsx'));
|
|
133
|
+
expect(router.some((s) => isFrom(s, 'expo-router'))).toBe(true);
|
|
134
|
+
const screen = moduleSpecifiers(read('tab-bar/expo-router/fading-tab-screen.tsx'));
|
|
135
|
+
expect(screen).toContain('react-native-screens');
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('the default entry imports the platform pieces BY BARE NAME (Metro picks .native)', () => {
|
|
139
|
+
const specifiers = moduleSpecifiers(read('tab-bar/index.ts'));
|
|
140
|
+
expect(specifiers).toContain('./surface');
|
|
141
|
+
expect(specifiers).toContain('./glyph');
|
|
142
|
+
expect(specifiers).toContain('../progressive-blur');
|
|
143
|
+
// A `.web` path here would pin every platform to the web fork.
|
|
144
|
+
expect(specifiers).not.toContain('./surface.web');
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('the web entry imports the web pieces by their FULL .web name', () => {
|
|
148
|
+
// Inside the published `lib/` every file is plain `.js`, and no web bundler
|
|
149
|
+
// resolves a bare `./surface` to the `.web` sibling — only Metro does.
|
|
150
|
+
const specifiers = moduleSpecifiers(read('tab-bar/index.web.tsx'));
|
|
151
|
+
expect(specifiers).toContain('./surface.web');
|
|
152
|
+
expect(specifiers).toContain('../progressive-blur/index.web');
|
|
153
|
+
expect(specifiers).not.toContain('./surface');
|
|
154
|
+
// `./glyph` has no web fork: the neutral file already renders `item.icon`,
|
|
155
|
+
// which is the correct web behaviour.
|
|
156
|
+
expect(specifiers).toContain('./glyph');
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
describe('tab-bar published surface', () => {
|
|
161
|
+
const pkg = JSON.parse(readFileSync(join(REPO_ROOT, 'package.json'), 'utf8')) as {
|
|
162
|
+
exports: Record<string, { browser?: { import?: string; require?: string } }>;
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
it('exports ./tab-bar with a browser condition → index.web.js', () => {
|
|
166
|
+
const entry = pkg.exports['./tab-bar'];
|
|
167
|
+
expect(entry).toBeDefined();
|
|
168
|
+
expect(entry?.browser?.import).toBe('./lib/module/tab-bar/index.web.js');
|
|
169
|
+
expect(entry?.browser?.require).toBe('./lib/commonjs/tab-bar/index.web.js');
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('exports ./progressive-blur with a browser condition → index.web.js', () => {
|
|
173
|
+
expect(pkg.exports['./progressive-blur']?.browser?.import).toBe(
|
|
174
|
+
'./lib/module/progressive-blur/index.web.js',
|
|
175
|
+
);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('exports ./tab-bar/expo-router with NO browser condition', () => {
|
|
179
|
+
// The router adapter is universal — it only re-binds `TabBar`/`TabBarButton`,
|
|
180
|
+
// whose own entry already resolves per platform. There is no `.web` sibling,
|
|
181
|
+
// so a browser condition would point at a file bob never emits.
|
|
182
|
+
const entry = pkg.exports['./tab-bar/expo-router'];
|
|
183
|
+
expect(entry).toBeDefined();
|
|
184
|
+
expect(entry?.browser).toBeUndefined();
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('the generator lists exactly the right subpaths as web-forked', () => {
|
|
188
|
+
const gen = readFileSync(join(REPO_ROOT, 'scripts/generate-platform-exports.mjs'), 'utf8');
|
|
189
|
+
const block = /const WEB_FORKED_SUBPATHS = new Set\(\[([\s\S]*?)\]\);/.exec(gen)?.[1];
|
|
190
|
+
expect(block).toBeDefined();
|
|
191
|
+
const listed = [...(block ?? '').matchAll(/^\s*'([^']+)',/gm)].map((m) => m[1]);
|
|
192
|
+
expect(listed).toContain('./tab-bar');
|
|
193
|
+
expect(listed).toContain('./progressive-blur');
|
|
194
|
+
// `assertWebSourceExists()` throws for this one — it has no `.web` sibling.
|
|
195
|
+
expect(listed).not.toContain('./tab-bar/expo-router');
|
|
196
|
+
});
|
|
197
|
+
});
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Text } from 'react-native';
|
|
3
|
+
import { fireEvent, render } from '@testing-library/react-native';
|
|
4
|
+
|
|
5
|
+
import { BloomThemeProvider } from '../theme/BloomThemeProvider';
|
|
6
|
+
import { ToastContent } from '../toast/ToastContent';
|
|
7
|
+
import type { ToastVariant } from '../toast/types';
|
|
8
|
+
|
|
9
|
+
const renderContent = (
|
|
10
|
+
props: Partial<React.ComponentProps<typeof ToastContent>> = {},
|
|
11
|
+
) => {
|
|
12
|
+
const onDismiss = jest.fn();
|
|
13
|
+
const utils = render(
|
|
14
|
+
<BloomThemeProvider mode="light" colorPreset="teal">
|
|
15
|
+
<ToastContent
|
|
16
|
+
id={1}
|
|
17
|
+
title="Saved"
|
|
18
|
+
unstyled={false}
|
|
19
|
+
icons={{}}
|
|
20
|
+
onDismiss={onDismiss}
|
|
21
|
+
{...props}
|
|
22
|
+
/>
|
|
23
|
+
</BloomThemeProvider>,
|
|
24
|
+
);
|
|
25
|
+
return { ...utils, onDismiss };
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* `ReactTestInstance['type']` is `ElementType`, whose string arm is
|
|
30
|
+
* `keyof JSX.IntrinsicElements` — so comparing it to a React Native host name
|
|
31
|
+
* ('Pressable', 'Svg', …) is a type error. Normalise to a plain string instead of
|
|
32
|
+
* asserting the type away.
|
|
33
|
+
*/
|
|
34
|
+
const hostName = (node: { type: unknown }): string =>
|
|
35
|
+
typeof node.type === 'string' ? node.type : '';
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* `*ByRole` does not resolve through this repo's `react-native` mock (it renders
|
|
39
|
+
* primitives as bare host elements), so button assertions go by component type.
|
|
40
|
+
*/
|
|
41
|
+
const pressablesOf = ({ UNSAFE_root }: ReturnType<typeof renderContent>) =>
|
|
42
|
+
UNSAFE_root.findAll((node) => hostName(node) === 'Pressable');
|
|
43
|
+
|
|
44
|
+
/** Bloom icons render as `Svg` hosts. */
|
|
45
|
+
const iconsOf = ({ UNSAFE_root }: ReturnType<typeof renderContent>) =>
|
|
46
|
+
UNSAFE_root.findAll((node) => hostName(node) === 'Svg');
|
|
47
|
+
|
|
48
|
+
const spinnersOf = ({ UNSAFE_root }: ReturnType<typeof renderContent>) =>
|
|
49
|
+
UNSAFE_root.findAll((node) => hostName(node) === 'ActivityIndicator');
|
|
50
|
+
|
|
51
|
+
describe('ToastContent', () => {
|
|
52
|
+
it('renders the title', () => {
|
|
53
|
+
const { getByText } = renderContent();
|
|
54
|
+
expect(getByText('Saved')).toBeTruthy();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('renders a description only when one is given', () => {
|
|
58
|
+
expect(renderContent().queryByText('Details')).toBeNull();
|
|
59
|
+
expect(
|
|
60
|
+
renderContent({ description: 'Details' }).getByText('Details'),
|
|
61
|
+
).toBeTruthy();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('renders an action button and calls onClick', () => {
|
|
65
|
+
const onClick = jest.fn();
|
|
66
|
+
const { getByText } = renderContent({
|
|
67
|
+
action: { label: 'Undo', onClick },
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
fireEvent.press(getByText('Undo'));
|
|
71
|
+
expect(onClick).toHaveBeenCalledTimes(1);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('renders an action supplied as a node instead of a label/onClick pair', () => {
|
|
75
|
+
const { getByText } = renderContent({
|
|
76
|
+
action: <Text>Custom action</Text>,
|
|
77
|
+
});
|
|
78
|
+
expect(getByText('Custom action')).toBeTruthy();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('dismisses after running the cancel handler', () => {
|
|
82
|
+
const onClick = jest.fn();
|
|
83
|
+
const { getByText, onDismiss } = renderContent({
|
|
84
|
+
cancel: { label: 'Dismiss', onClick },
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
fireEvent.press(getByText('Dismiss'));
|
|
88
|
+
expect(onClick).toHaveBeenCalledTimes(1);
|
|
89
|
+
expect(onDismiss).toHaveBeenCalledWith(1);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('shows no button row when there is neither action nor cancel', () => {
|
|
93
|
+
expect(pressablesOf(renderContent())).toHaveLength(0);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('renders the close button only when asked, and it dismisses', () => {
|
|
97
|
+
expect(pressablesOf(renderContent({ dismissible: true }))).toHaveLength(0);
|
|
98
|
+
|
|
99
|
+
const rendered = renderContent({ dismissible: true, closeButton: true });
|
|
100
|
+
const [closeButton] = pressablesOf(rendered);
|
|
101
|
+
expect(closeButton).toBeDefined();
|
|
102
|
+
if (closeButton) {
|
|
103
|
+
fireEvent.press(closeButton);
|
|
104
|
+
}
|
|
105
|
+
expect(rendered.onDismiss).toHaveBeenCalledWith(1);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('never renders a close button on a non-dismissible toast', () => {
|
|
109
|
+
expect(
|
|
110
|
+
pressablesOf(renderContent({ dismissible: false, closeButton: true })),
|
|
111
|
+
).toHaveLength(0);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('prefers a caller-supplied close node over the default button', () => {
|
|
115
|
+
const { getByText } = renderContent({
|
|
116
|
+
dismissible: true,
|
|
117
|
+
closeButton: true,
|
|
118
|
+
close: <Text>Bye</Text>,
|
|
119
|
+
});
|
|
120
|
+
expect(getByText('Bye')).toBeTruthy();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('renders a variant icon, and none for a variant-less toast', () => {
|
|
124
|
+
// A neutral toast has no leading icon at all.
|
|
125
|
+
expect(iconsOf(renderContent({ variant: 'success' })).length).toBeGreaterThan(
|
|
126
|
+
iconsOf(renderContent()).length,
|
|
127
|
+
);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it.each<ToastVariant>(['success', 'error', 'warning', 'info'])(
|
|
131
|
+
'renders an icon for the %s variant',
|
|
132
|
+
(variant) => {
|
|
133
|
+
expect(iconsOf(renderContent({ variant })).length).toBeGreaterThan(0);
|
|
134
|
+
},
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
it('uses a spinner instead of an icon while a promise is pending', () => {
|
|
138
|
+
const rendered = renderContent({
|
|
139
|
+
promiseOptions: {
|
|
140
|
+
promise: Promise.resolve('done'),
|
|
141
|
+
loading: 'Saving…',
|
|
142
|
+
error: 'Failed',
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
expect(spinnersOf(rendered)).toHaveLength(1);
|
|
146
|
+
expect(iconsOf(rendered)).toHaveLength(0);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('lets the outlet override the loading indicator', () => {
|
|
150
|
+
const { getByText } = renderContent({
|
|
151
|
+
variant: 'loading',
|
|
152
|
+
icons: { loading: <Text>spinning</Text> },
|
|
153
|
+
});
|
|
154
|
+
expect(getByText('spinning')).toBeTruthy();
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('lets the outlet override a variant icon', () => {
|
|
158
|
+
const { getByText } = renderContent({
|
|
159
|
+
variant: 'success',
|
|
160
|
+
icons: { success: <Text>yay</Text> },
|
|
161
|
+
});
|
|
162
|
+
expect(getByText('yay')).toBeTruthy();
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('prefers a per-toast icon over the variant icon', () => {
|
|
166
|
+
const { getByText } = renderContent({
|
|
167
|
+
variant: 'success',
|
|
168
|
+
icon: <Text>mine</Text>,
|
|
169
|
+
icons: { success: <Text>yay</Text> },
|
|
170
|
+
});
|
|
171
|
+
expect(getByText('mine')).toBeTruthy();
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('applies caller style overrides to the title', () => {
|
|
175
|
+
const { getByText } = renderContent({
|
|
176
|
+
styles: { title: { fontSize: 99 } },
|
|
177
|
+
});
|
|
178
|
+
expect(getByText('Saved').props.style).toEqual(
|
|
179
|
+
expect.arrayContaining([{ fontSize: 99 }]),
|
|
180
|
+
);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('drops its own surface and text styling when unstyled', () => {
|
|
184
|
+
const { getByText } = renderContent({ unstyled: true });
|
|
185
|
+
// Only the (absent) override slot remains, so nothing carries a colour.
|
|
186
|
+
expect(getByText('Saved').props.style).toEqual([
|
|
187
|
+
undefined,
|
|
188
|
+
undefined,
|
|
189
|
+
undefined,
|
|
190
|
+
]);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Source/contract guards for the toast host split, mirroring
|
|
6
|
+
* `BottomSheetWebFork.test.ts`.
|
|
7
|
+
*
|
|
8
|
+
* The toast engine is ONE universal implementation; its only platform split is
|
|
9
|
+
* the host. Several of the properties below cannot be reproduced in jest (the
|
|
10
|
+
* real paint, the portal ancestry, Metro's `.native` resolution), so they are
|
|
11
|
+
* asserted against the source and the generated packaging instead, and verified
|
|
12
|
+
* for real in a browser and on a device.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const SRC = join(__dirname, '..');
|
|
16
|
+
const REPO_ROOT = join(SRC, '..');
|
|
17
|
+
|
|
18
|
+
const read = (rel: string) => readFileSync(join(SRC, rel), 'utf8');
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Source with comments removed. These files deliberately DOCUMENT the patterns
|
|
22
|
+
* they must not contain (`ToastHost.native.tsx` shows a consumer how to inject
|
|
23
|
+
* `FullWindowOverlay`; `Positioner.tsx` explains why it holds no `position:
|
|
24
|
+
* 'fixed'`), so every negative assertion runs against code only.
|
|
25
|
+
*/
|
|
26
|
+
const code = (rel: string) =>
|
|
27
|
+
read(rel)
|
|
28
|
+
.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
29
|
+
.replace(/^\s*\/\/.*$/gm, '');
|
|
30
|
+
|
|
31
|
+
describe('ToastHost platform split', () => {
|
|
32
|
+
it('web/default host portals into the shared bloom portal root', () => {
|
|
33
|
+
const host = read('toast/ToastHost.tsx');
|
|
34
|
+
expect(host).toMatch(/from '\.\.\/portal\/index\.web'/);
|
|
35
|
+
expect(host).toMatch(/<Portal>/);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('web/default host provides its own GestureHandlerRootView (W8)', () => {
|
|
39
|
+
const host = read('toast/ToastHost.tsx');
|
|
40
|
+
// Portaled content sits outside the app-root GHRV, so swipe-to-dismiss
|
|
41
|
+
// would never receive touches without this.
|
|
42
|
+
expect(host).toMatch(
|
|
43
|
+
/import \{ GestureHandlerRootView \} from 'react-native-gesture-handler'/,
|
|
44
|
+
);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('web/default host anchors to the viewport through the shared style module (W7)', () => {
|
|
48
|
+
const host = code('toast/ToastHost.tsx');
|
|
49
|
+
expect(host).toMatch(/position: WEB_POSITION_FIXED/);
|
|
50
|
+
expect(host).toMatch(/from '\.\.\/styles\/web-view-style'/);
|
|
51
|
+
// The one-off inline cast this replaces must never come back.
|
|
52
|
+
expect(host).not.toMatch(/'fixed' as/);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('web/default host layers toasts at Z_INDEX.toast', () => {
|
|
56
|
+
const host = read('toast/ToastHost.tsx');
|
|
57
|
+
expect(host).toMatch(/zIndex: Z_INDEX\.toast/);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('native host imports neither react-native-screens nor the portal (D6)', () => {
|
|
61
|
+
const native = code('toast/ToastHost.native.tsx');
|
|
62
|
+
expect(native).not.toMatch(/from 'react-native-screens'/);
|
|
63
|
+
expect(native).not.toMatch(/from '\.\.\/portal/);
|
|
64
|
+
expect(native).toMatch(/ToasterOverlayWrapper/);
|
|
65
|
+
// The doc comment still has to tell consumers how to inject it themselves.
|
|
66
|
+
expect(read('toast/ToastHost.native.tsx')).toMatch(/FullWindowOverlay/);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('the shared style module owns the only fixed-position assertion', () => {
|
|
70
|
+
const styleModule = read('styles/web-view-style.ts');
|
|
71
|
+
expect(styleModule).toMatch(
|
|
72
|
+
/export const WEB_POSITION_FIXED = 'fixed' as ViewStyle\['position'\]/,
|
|
73
|
+
);
|
|
74
|
+
// Exactly one cast in the module, and nothing else exported alongside it.
|
|
75
|
+
// (Counted against code — the doc comment discusses casts in prose.)
|
|
76
|
+
expect(code('styles/web-view-style.ts').match(/ as /g)).toHaveLength(1);
|
|
77
|
+
expect(styleModule.match(/^export /gm)).toHaveLength(1);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('no engine file other than the host reaches for a platform overlay', () => {
|
|
81
|
+
for (const file of [
|
|
82
|
+
'toast/Toaster.tsx',
|
|
83
|
+
'toast/Positioner.tsx',
|
|
84
|
+
'toast/ToastRow.tsx',
|
|
85
|
+
]) {
|
|
86
|
+
const source = code(file);
|
|
87
|
+
expect(source).not.toMatch(/from 'react-native-screens'/);
|
|
88
|
+
// Doc comments explain why `fixed` lives in the host; assert no file here
|
|
89
|
+
// actually POSITIONS anything fixed.
|
|
90
|
+
expect(source).not.toMatch(/position:\s*'fixed'/);
|
|
91
|
+
expect(source).not.toMatch(/webPosition\(/);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('never returns an animation from a mapper (reanimated web failure mode A)', () => {
|
|
96
|
+
// `useDerivedValue(() => withTiming(...))` and a `withTiming` returned from
|
|
97
|
+
// inside `useAnimatedStyle` do not tick on web: the value jumps to a static
|
|
98
|
+
// frame. Every animation must be ASSIGNED from JS instead — the row's shared
|
|
99
|
+
// values come from `useAnimatedTarget`, and its mappers only read them.
|
|
100
|
+
for (const file of [
|
|
101
|
+
'toast/ToastRow.tsx',
|
|
102
|
+
'toast/use-toast-position.ts',
|
|
103
|
+
'toast/ToastSwipeHandler.tsx',
|
|
104
|
+
]) {
|
|
105
|
+
const source = code(file);
|
|
106
|
+
expect(source).not.toMatch(/useDerivedValue/);
|
|
107
|
+
expect(source).not.toMatch(/return withTiming/);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const driver = code('toast/use-animated-target.ts');
|
|
111
|
+
expect(driver).toMatch(/value\.value = withTiming\(/);
|
|
112
|
+
expect(driver).not.toMatch(/useDerivedValue/);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('Positioner passes pointerEvents through style, not as a prop', () => {
|
|
116
|
+
const positioner = code('toast/Positioner.tsx');
|
|
117
|
+
expect(positioner).toMatch(/pointerEvents:/);
|
|
118
|
+
expect(positioner).not.toMatch(/pointerEvents=\{/);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('package.json exports ./toast WITHOUT a browser condition', () => {
|
|
122
|
+
const pkg = JSON.parse(readFileSync(join(REPO_ROOT, 'package.json'), 'utf8')) as {
|
|
123
|
+
exports: Record<string, { browser?: unknown; import?: { default?: string } }>;
|
|
124
|
+
};
|
|
125
|
+
const entry = pkg.exports['./toast'];
|
|
126
|
+
expect(entry).toBeDefined();
|
|
127
|
+
// A browser condition would emit lib/module/toast/index.web.js, and any
|
|
128
|
+
// bundler with `.web.js` in resolve.extensions would resolve `./toast` to it.
|
|
129
|
+
expect(entry?.browser).toBeUndefined();
|
|
130
|
+
expect(entry?.import?.default).toBe('./lib/module/toast/index.js');
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('the generator no longer lists ./toast as web-forked', () => {
|
|
134
|
+
const generator = readFileSync(
|
|
135
|
+
join(REPO_ROOT, 'scripts/generate-platform-exports.mjs'),
|
|
136
|
+
'utf8',
|
|
137
|
+
);
|
|
138
|
+
const forkedBlock = /const WEB_FORKED_SUBPATHS = new Set\(\[([\s\S]*?)\]\)/.exec(
|
|
139
|
+
generator,
|
|
140
|
+
);
|
|
141
|
+
expect(forkedBlock).not.toBeNull();
|
|
142
|
+
expect(forkedBlock?.[1]).not.toMatch(/^\s*'\.\/toast',/m);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('no sonner import survives in the toast surface or the root barrel', () => {
|
|
146
|
+
for (const file of [
|
|
147
|
+
'toast/index.tsx',
|
|
148
|
+
'toast/Toaster.tsx',
|
|
149
|
+
'toast/toast-fns.ts',
|
|
150
|
+
'index.ts',
|
|
151
|
+
]) {
|
|
152
|
+
expect(code(file)).not.toMatch(/from 'sonner(-native)?'/);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
});
|