@oxyhq/bloom 0.50.2 → 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 +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/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.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/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/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.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/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.web.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.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/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.web.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.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/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 +3 -2
- package/src/context-menu/index.web.tsx +3 -2
- package/src/dialog/Dialog.web.tsx +4 -3
- 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.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/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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oxyhq/bloom",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.51.0",
|
|
4
4
|
"description": "Bloom UI — Oxy ecosystem component library for React Native + Expo + Web",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
@@ -334,11 +334,6 @@
|
|
|
334
334
|
},
|
|
335
335
|
"./toast": {
|
|
336
336
|
"react-native": "./src/toast/index.tsx",
|
|
337
|
-
"browser": {
|
|
338
|
-
"types": "./lib/typescript/module/toast/index.web.d.ts",
|
|
339
|
-
"import": "./lib/module/toast/index.web.js",
|
|
340
|
-
"require": "./lib/commonjs/toast/index.web.js"
|
|
341
|
-
},
|
|
342
337
|
"import": {
|
|
343
338
|
"types": "./lib/typescript/module/toast/index.d.ts",
|
|
344
339
|
"default": "./lib/module/toast/index.js"
|
|
@@ -1012,12 +1007,56 @@
|
|
|
1012
1007
|
"default": "./lib/commonjs/list/index.js"
|
|
1013
1008
|
}
|
|
1014
1009
|
},
|
|
1010
|
+
"./tab-bar": {
|
|
1011
|
+
"react-native": "./src/tab-bar/index.ts",
|
|
1012
|
+
"browser": {
|
|
1013
|
+
"types": "./lib/typescript/module/tab-bar/index.web.d.ts",
|
|
1014
|
+
"import": "./lib/module/tab-bar/index.web.js",
|
|
1015
|
+
"require": "./lib/commonjs/tab-bar/index.web.js"
|
|
1016
|
+
},
|
|
1017
|
+
"import": {
|
|
1018
|
+
"types": "./lib/typescript/module/tab-bar/index.d.ts",
|
|
1019
|
+
"default": "./lib/module/tab-bar/index.js"
|
|
1020
|
+
},
|
|
1021
|
+
"require": {
|
|
1022
|
+
"types": "./lib/typescript/commonjs/tab-bar/index.d.ts",
|
|
1023
|
+
"default": "./lib/commonjs/tab-bar/index.js"
|
|
1024
|
+
}
|
|
1025
|
+
},
|
|
1026
|
+
"./tab-bar/expo-router": {
|
|
1027
|
+
"react-native": "./src/tab-bar/expo-router/index.ts",
|
|
1028
|
+
"import": {
|
|
1029
|
+
"types": "./lib/typescript/module/tab-bar/expo-router/index.d.ts",
|
|
1030
|
+
"default": "./lib/module/tab-bar/expo-router/index.js"
|
|
1031
|
+
},
|
|
1032
|
+
"require": {
|
|
1033
|
+
"types": "./lib/typescript/commonjs/tab-bar/expo-router/index.d.ts",
|
|
1034
|
+
"default": "./lib/commonjs/tab-bar/expo-router/index.js"
|
|
1035
|
+
}
|
|
1036
|
+
},
|
|
1037
|
+
"./progressive-blur": {
|
|
1038
|
+
"react-native": "./src/progressive-blur/index.tsx",
|
|
1039
|
+
"browser": {
|
|
1040
|
+
"types": "./lib/typescript/module/progressive-blur/index.web.d.ts",
|
|
1041
|
+
"import": "./lib/module/progressive-blur/index.web.js",
|
|
1042
|
+
"require": "./lib/commonjs/progressive-blur/index.web.js"
|
|
1043
|
+
},
|
|
1044
|
+
"import": {
|
|
1045
|
+
"types": "./lib/typescript/module/progressive-blur/index.d.ts",
|
|
1046
|
+
"default": "./lib/module/progressive-blur/index.js"
|
|
1047
|
+
},
|
|
1048
|
+
"require": {
|
|
1049
|
+
"types": "./lib/typescript/commonjs/progressive-blur/index.d.ts",
|
|
1050
|
+
"default": "./lib/commonjs/progressive-blur/index.js"
|
|
1051
|
+
}
|
|
1052
|
+
},
|
|
1015
1053
|
"./design-tokens/theme.css": "./src/design-tokens/theme.css",
|
|
1016
1054
|
"./package.json": "./package.json"
|
|
1017
1055
|
},
|
|
1018
1056
|
"files": [
|
|
1019
1057
|
"src",
|
|
1020
|
-
"lib"
|
|
1058
|
+
"lib",
|
|
1059
|
+
"NOTICE"
|
|
1021
1060
|
],
|
|
1022
1061
|
"keywords": [
|
|
1023
1062
|
"react-native",
|
|
@@ -1088,8 +1127,8 @@
|
|
|
1088
1127
|
"typescript": "tsc --noEmit",
|
|
1089
1128
|
"pretypescript": "node scripts/generate-font-data.mjs",
|
|
1090
1129
|
"clean": "rm -rf lib",
|
|
1091
|
-
"prepack": "bun run clean &&
|
|
1092
|
-
"prepare": "
|
|
1130
|
+
"prepack": "bun run clean && bun run build",
|
|
1131
|
+
"prepare": "bun run build || true",
|
|
1093
1132
|
"release": "rm -rf lib && bun run build && release-it",
|
|
1094
1133
|
"storybook": "storybook dev -p 6006 --no-open",
|
|
1095
1134
|
"storybook:build": "storybook build -o storybook-static"
|
|
@@ -1121,9 +1160,11 @@
|
|
|
1121
1160
|
"@vitejs/plugin-react": "^6.0.2",
|
|
1122
1161
|
"expo-blur": "~56.0.3",
|
|
1123
1162
|
"expo-font": "^56.0.5",
|
|
1163
|
+
"expo-glass-effect": "~56.0.4",
|
|
1124
1164
|
"expo-haptics": "~56.0.3",
|
|
1125
1165
|
"expo-image": "~56.0.11",
|
|
1126
1166
|
"expo-router": "^56.0.0",
|
|
1167
|
+
"expo-symbols": "~56.0.6",
|
|
1127
1168
|
"jest": "^30.3.0",
|
|
1128
1169
|
"jest-environment-jsdom": "^30.4.1",
|
|
1129
1170
|
"react": "19.2.0",
|
|
@@ -1131,14 +1172,14 @@
|
|
|
1131
1172
|
"react-native": "0.83.2",
|
|
1132
1173
|
"react-native-builder-bob": "^0.40.16",
|
|
1133
1174
|
"react-native-gesture-handler": "^2.30.0",
|
|
1134
|
-
"react-native-reanimated": "^4.
|
|
1175
|
+
"react-native-reanimated": "^4.5.0",
|
|
1135
1176
|
"react-native-safe-area-context": "~5.6.0",
|
|
1177
|
+
"react-native-screens": "^4.25.2",
|
|
1136
1178
|
"react-native-svg": "^15.15.3",
|
|
1137
1179
|
"react-native-web": "^0.21.2",
|
|
1180
|
+
"react-native-worklets": "0.10.0",
|
|
1138
1181
|
"react-test-renderer": "^19.2.0",
|
|
1139
1182
|
"release-it": "^19.0.6",
|
|
1140
|
-
"sonner": "^2.0.3",
|
|
1141
|
-
"sonner-native": "^0.23.1",
|
|
1142
1183
|
"storybook": "^10",
|
|
1143
1184
|
"ts-jest": "^29.4.6",
|
|
1144
1185
|
"typescript": "~5.9.2",
|
|
@@ -1148,18 +1189,19 @@
|
|
|
1148
1189
|
"expo": "*",
|
|
1149
1190
|
"expo-blur": "*",
|
|
1150
1191
|
"expo-font": "*",
|
|
1192
|
+
"expo-glass-effect": ">=0.1.5",
|
|
1151
1193
|
"expo-haptics": "*",
|
|
1152
1194
|
"expo-image": "*",
|
|
1153
1195
|
"expo-router": ">=3.0.0",
|
|
1196
|
+
"expo-symbols": ">=0.4.5",
|
|
1154
1197
|
"react": ">=18.0.0",
|
|
1155
1198
|
"react-dom": ">=18.0.0",
|
|
1156
1199
|
"react-native": ">=0.73.0",
|
|
1157
|
-
"react-native-gesture-handler": ">=2.
|
|
1158
|
-
"react-native-reanimated": ">=3.
|
|
1200
|
+
"react-native-gesture-handler": ">=2.16.1",
|
|
1201
|
+
"react-native-reanimated": ">=3.13.0",
|
|
1159
1202
|
"react-native-safe-area-context": ">=5.0.0",
|
|
1203
|
+
"react-native-screens": ">=3.16.0",
|
|
1160
1204
|
"react-native-svg": ">=13.0.0",
|
|
1161
|
-
"sonner": ">=2.0.0",
|
|
1162
|
-
"sonner-native": ">=0.17.0",
|
|
1163
1205
|
"nativewind": ">=5.0.0"
|
|
1164
1206
|
},
|
|
1165
1207
|
"peerDependenciesMeta": {
|
|
@@ -1169,22 +1211,19 @@
|
|
|
1169
1211
|
"expo-font": {
|
|
1170
1212
|
"optional": true
|
|
1171
1213
|
},
|
|
1172
|
-
"expo-
|
|
1173
|
-
"optional": true
|
|
1174
|
-
},
|
|
1175
|
-
"expo-router": {
|
|
1214
|
+
"expo-glass-effect": {
|
|
1176
1215
|
"optional": true
|
|
1177
1216
|
},
|
|
1178
|
-
"
|
|
1217
|
+
"expo-haptics": {
|
|
1179
1218
|
"optional": true
|
|
1180
1219
|
},
|
|
1181
|
-
"
|
|
1220
|
+
"expo-router": {
|
|
1182
1221
|
"optional": true
|
|
1183
1222
|
},
|
|
1184
|
-
"
|
|
1223
|
+
"expo-symbols": {
|
|
1185
1224
|
"optional": true
|
|
1186
1225
|
},
|
|
1187
|
-
"
|
|
1226
|
+
"react-dom": {
|
|
1188
1227
|
"optional": true
|
|
1189
1228
|
},
|
|
1190
1229
|
"nativewind": {
|
|
@@ -1218,7 +1257,6 @@
|
|
|
1218
1257
|
},
|
|
1219
1258
|
"dependencies": {
|
|
1220
1259
|
"@tanstack/react-virtual": "^3.14.3",
|
|
1221
|
-
"nanoid": "^5.1.5",
|
|
1222
1260
|
"react-native-css": "3.0.7",
|
|
1223
1261
|
"react-remove-scroll-bar": "^2.3.8"
|
|
1224
1262
|
},
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { ReactTestInstance } from 'react-test-renderer';
|
|
3
|
+
import { fireEvent, render } from '@testing-library/react-native';
|
|
4
|
+
|
|
5
|
+
import { BloomThemeProvider } from '../theme/BloomThemeProvider';
|
|
6
|
+
import type { ThemeColors } from '../theme/types';
|
|
7
|
+
import { useTheme } from '../theme/use-theme';
|
|
8
|
+
import { TabBar, TabBarButton } from '../tab-bar';
|
|
9
|
+
import { TabBarGlyph as NativeTabBarGlyph } from '../tab-bar/glyph.native';
|
|
10
|
+
import { resolveTabBarTheme } from '../tab-bar/shared';
|
|
11
|
+
import { TabBarSurface as NativeTabBarSurface } from '../tab-bar/surface.native';
|
|
12
|
+
import type { TabBarItem, TabBarTheme } from '../tab-bar/types';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Behaviour tests for the floating tab bar.
|
|
16
|
+
*
|
|
17
|
+
* Three properties of the environment shape every assertion here:
|
|
18
|
+
*
|
|
19
|
+
* 1. Jest has no platform-extension resolution, so `../tab-bar` binds the
|
|
20
|
+
* NEUTRAL `surface.tsx` / `glyph.tsx`. The two `.native` variants are pulled
|
|
21
|
+
* in by their full path where they are asserted on directly — which is also
|
|
22
|
+
* what makes the `expo-glass-effect` / `expo-symbols` mocks load-bearing
|
|
23
|
+
* rather than decorative.
|
|
24
|
+
* 2. Labels render through `Animated.Text`, a plain host string under the
|
|
25
|
+
* reanimated mock, so testing-library's text queries cannot see them.
|
|
26
|
+
* `labelFor` walks the tree instead.
|
|
27
|
+
* 3. The reanimated mock's shared values are plain boxes: writing
|
|
28
|
+
* `slideIndex.value` does NOT re-render, and `useAnimatedStyle` runs during
|
|
29
|
+
* render. A mapper reading a shared value that an EFFECT wrote therefore
|
|
30
|
+
* reflects the write only on the NEXT render — hence `renderSettled`. The
|
|
31
|
+
* motion itself is verified in a real browser, not here.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Stand-in for a Bloom icon element: a host node tagged with the `fill` it was
|
|
36
|
+
* cloned with, so a test can read back the tint the bar injected through
|
|
37
|
+
* `applyIconColor`.
|
|
38
|
+
*/
|
|
39
|
+
function BareIcon({ id, fill }: { id: string; fill?: string }) {
|
|
40
|
+
return React.createElement('bloom-test-icon', { testID: id, fill });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const ITEMS: TabBarItem[] = [
|
|
44
|
+
{ name: 'home', label: 'Home', icon: <BareIcon id="home-icon" /> },
|
|
45
|
+
{ name: 'search', label: 'Search', icon: <BareIcon id="search-icon" /> },
|
|
46
|
+
{ name: 'you', label: 'You', icon: <BareIcon id="you-icon" /> },
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
/** Captures the live `ThemeColors` so assertions compare against real tokens. */
|
|
50
|
+
function ThemeProbe({ onColors }: { onColors: (colors: ThemeColors) => void }) {
|
|
51
|
+
onColors(useTheme().colors);
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function withTheme(ui: React.ReactElement) {
|
|
56
|
+
return (
|
|
57
|
+
<BloomThemeProvider mode="light" colorPreset="teal">
|
|
58
|
+
{ui}
|
|
59
|
+
</BloomThemeProvider>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function renderWithTheme(ui: React.ReactElement) {
|
|
64
|
+
return render(withTheme(ui));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Render, then re-render an equivalent tree so mappers see the shared-value
|
|
69
|
+
* writes the mount effects made. See note 3 in the file header.
|
|
70
|
+
*
|
|
71
|
+
* Takes a FACTORY, not an element: React bails out of re-rendering a
|
|
72
|
+
* referentially identical element, which would skip the second pass entirely
|
|
73
|
+
* and silently leave the assertion reading first-frame values.
|
|
74
|
+
*/
|
|
75
|
+
function renderSettled(ui: () => React.ReactElement) {
|
|
76
|
+
const utils = renderWithTheme(ui());
|
|
77
|
+
utils.rerender(withTheme(ui()));
|
|
78
|
+
return utils;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** The theme the bar resolves for `mode="light" colorPreset="teal"`. */
|
|
82
|
+
function readTheme(overrides?: Partial<TabBarTheme>): TabBarTheme {
|
|
83
|
+
let resolved: TabBarTheme | undefined;
|
|
84
|
+
renderWithTheme(
|
|
85
|
+
<ThemeProbe
|
|
86
|
+
onColors={(colors) => {
|
|
87
|
+
resolved = resolveTabBarTheme(colors, overrides);
|
|
88
|
+
}}
|
|
89
|
+
/>,
|
|
90
|
+
);
|
|
91
|
+
if (!resolved) throw new Error('ThemeProbe never ran');
|
|
92
|
+
return resolved;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Flatten a (possibly nested / conditional) RN style prop into one object.
|
|
96
|
+
function flattenStyle(style: unknown): Record<string, unknown> {
|
|
97
|
+
const out: Record<string, unknown> = {};
|
|
98
|
+
const visit = (s: unknown): void => {
|
|
99
|
+
if (Array.isArray(s)) s.forEach(visit);
|
|
100
|
+
else if (s && typeof s === 'object') Object.assign(out, s);
|
|
101
|
+
};
|
|
102
|
+
visit(style);
|
|
103
|
+
return out;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* The host tag a node renders as, or `null` for a composite.
|
|
108
|
+
*
|
|
109
|
+
* `ReactTestInstance['type']` is typed as `ElementType`, whose string arm is the
|
|
110
|
+
* union of KNOWN intrinsic tags — so comparing it directly to a mock host name
|
|
111
|
+
* like `'Animated.Text'` is a TS2367 "no overlap" error. Widening to `string`
|
|
112
|
+
* behind this accessor is the honest fix: these really are host tags, they are
|
|
113
|
+
* just ones the RN/reanimated mocks invent.
|
|
114
|
+
*/
|
|
115
|
+
function hostName(node: ReactTestInstance): string | null {
|
|
116
|
+
const { type } = node;
|
|
117
|
+
return typeof type === 'string' ? type : null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Every tab trigger, in bar order.
|
|
122
|
+
*
|
|
123
|
+
* Restricted to HOST nodes: the tree carries both the composite `Pressable` and
|
|
124
|
+
* the host element it renders, and both hold the same props — counting them all
|
|
125
|
+
* would double every tab.
|
|
126
|
+
*/
|
|
127
|
+
function triggers(root: ReactTestInstance): ReactTestInstance[] {
|
|
128
|
+
return root.findAll(
|
|
129
|
+
(node) => hostName(node) !== null && node.props?.accessibilityRole === 'tab',
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** The `Animated.Text` label node of the tab whose text is `label`. */
|
|
134
|
+
function labelFor(root: ReactTestInstance, label: string): ReactTestInstance {
|
|
135
|
+
const found = root.findAll(
|
|
136
|
+
(node) => hostName(node) === 'Animated.Text' && node.props?.children === label,
|
|
137
|
+
);
|
|
138
|
+
const first = found[0];
|
|
139
|
+
if (!first) throw new Error(`No tab label rendered with text "${label}"`);
|
|
140
|
+
return first;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** Every host node rendered as `tag`. */
|
|
144
|
+
function hosts(root: ReactTestInstance, tag: string): ReactTestInstance[] {
|
|
145
|
+
return root.findAll((node) => hostName(node) === tag);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function selectedFlags(root: ReactTestInstance): boolean[] {
|
|
149
|
+
return triggers(root).map((node) => node.props.accessibilityState.selected);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function Bar({
|
|
153
|
+
activeIndex,
|
|
154
|
+
onIndexChange,
|
|
155
|
+
theme,
|
|
156
|
+
focusedIndex,
|
|
157
|
+
}: {
|
|
158
|
+
activeIndex?: number;
|
|
159
|
+
onIndexChange?: (index: number) => void;
|
|
160
|
+
theme?: Partial<TabBarTheme>;
|
|
161
|
+
/** When set, drives the FOCUS path (`isFocused`) instead of `activeIndex`. */
|
|
162
|
+
focusedIndex?: number;
|
|
163
|
+
}) {
|
|
164
|
+
return (
|
|
165
|
+
<TabBar activeIndex={activeIndex} onIndexChange={onIndexChange} theme={theme}>
|
|
166
|
+
{ITEMS.map((item, index) => (
|
|
167
|
+
<TabBarButton
|
|
168
|
+
key={item.name}
|
|
169
|
+
item={item}
|
|
170
|
+
index={index}
|
|
171
|
+
isFocused={focusedIndex === undefined ? undefined : focusedIndex === index}
|
|
172
|
+
/>
|
|
173
|
+
))}
|
|
174
|
+
</TabBar>
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
describe('TabBar', () => {
|
|
179
|
+
it('renders every item label', () => {
|
|
180
|
+
const { UNSAFE_root } = renderWithTheme(<Bar activeIndex={0} />);
|
|
181
|
+
for (const item of ITEMS) expect(labelFor(UNSAFE_root, item.label)).toBeTruthy();
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it("renders each item's own icon node, on both crossfade layers", () => {
|
|
185
|
+
const { getAllByTestId } = renderWithTheme(<Bar activeIndex={0} />);
|
|
186
|
+
// The bar renders the glyph twice per tab: an inactive layer with the
|
|
187
|
+
// active layer crossfading on top.
|
|
188
|
+
for (const id of ['home-icon', 'search-icon', 'you-icon']) {
|
|
189
|
+
expect(getAllByTestId(id)).toHaveLength(2);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('injects the layer tint as the icon fill, from theme tokens', () => {
|
|
194
|
+
const theme = readTheme();
|
|
195
|
+
const { getAllByTestId } = renderWithTheme(<Bar activeIndex={0} />);
|
|
196
|
+
const fills = getAllByTestId('home-icon').map((node) => node.props.fill);
|
|
197
|
+
expect(fills).toEqual(expect.arrayContaining([theme.inactiveTint, theme.activeTint]));
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('marks the tab at activeIndex as selected for accessibility', () => {
|
|
201
|
+
const { UNSAFE_root } = renderWithTheme(<Bar activeIndex={1} />);
|
|
202
|
+
expect(selectedFlags(UNSAFE_root)).toEqual([false, true, false]);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('moves the selection when activeIndex changes', () => {
|
|
206
|
+
const { UNSAFE_root, rerender } = renderWithTheme(<Bar activeIndex={0} />);
|
|
207
|
+
rerender(withTheme(<Bar activeIndex={2} />));
|
|
208
|
+
expect(selectedFlags(UNSAFE_root)).toEqual([false, false, true]);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it('tints the label of the tab the highlight sits on', () => {
|
|
212
|
+
const theme = readTheme();
|
|
213
|
+
const { UNSAFE_root } = renderSettled(() => <Bar activeIndex={1} />);
|
|
214
|
+
expect(flattenStyle(labelFor(UNSAFE_root, 'Search').props.style).color).toBe(theme.activeTint);
|
|
215
|
+
expect(flattenStyle(labelFor(UNSAFE_root, 'Home').props.style).color).toBe(theme.inactiveTint);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it('calls onIndexChange with the pressed index', () => {
|
|
219
|
+
const onIndexChange = jest.fn();
|
|
220
|
+
const { UNSAFE_root } = renderWithTheme(<Bar activeIndex={0} onIndexChange={onIndexChange} />);
|
|
221
|
+
fireEvent.press(triggers(UNSAFE_root)[2] as ReactTestInstance);
|
|
222
|
+
expect(onIndexChange).toHaveBeenCalledTimes(1);
|
|
223
|
+
expect(onIndexChange).toHaveBeenCalledWith(2);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('does not report the press itself on the focus-driven path', () => {
|
|
227
|
+
// With `isFocused` supplied the router trigger's own onPress navigates;
|
|
228
|
+
// reporting through the bar as well would navigate twice.
|
|
229
|
+
const onIndexChange = jest.fn();
|
|
230
|
+
const { UNSAFE_root } = renderWithTheme(
|
|
231
|
+
<Bar focusedIndex={0} onIndexChange={onIndexChange} />,
|
|
232
|
+
);
|
|
233
|
+
fireEvent.press(triggers(UNSAFE_root)[1] as ReactTestInstance);
|
|
234
|
+
expect(onIndexChange).not.toHaveBeenCalled();
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it('lets isFocused override the bar activeIndex', () => {
|
|
238
|
+
const { UNSAFE_root } = renderWithTheme(
|
|
239
|
+
<TabBar activeIndex={0}>
|
|
240
|
+
{ITEMS.map((item, index) => (
|
|
241
|
+
<TabBarButton key={item.name} item={item} index={index} isFocused={index === 2} />
|
|
242
|
+
))}
|
|
243
|
+
</TabBar>,
|
|
244
|
+
);
|
|
245
|
+
// Index 0 is the bar's activeIndex, but every button carries an explicit
|
|
246
|
+
// isFocused, so focus comes from the buttons alone.
|
|
247
|
+
expect(selectedFlags(UNSAFE_root)).toEqual([false, false, true]);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it('drives the highlight from isFocused when the bar is uncontrolled', () => {
|
|
251
|
+
const theme = readTheme();
|
|
252
|
+
// The router path: `RouterTabBarProps` omits `activeIndex` on purpose, so
|
|
253
|
+
// the focused BUTTON is the only writer of the highlight. This is what
|
|
254
|
+
// keeps the pill correct through deep links and back gestures.
|
|
255
|
+
const { UNSAFE_root } = renderSettled(() => <Bar focusedIndex={2} />);
|
|
256
|
+
// The label tint follows the sliding highlight, so it reports where the
|
|
257
|
+
// pill actually is.
|
|
258
|
+
expect(flattenStyle(labelFor(UNSAFE_root, 'You').props.style).color).toBe(theme.activeTint);
|
|
259
|
+
expect(flattenStyle(labelFor(UNSAFE_root, 'Home').props.style).color).toBe(theme.inactiveTint);
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
describe('theming', () => {
|
|
263
|
+
it('resolves its defaults from Bloom tokens, never a hardcoded palette', () => {
|
|
264
|
+
const theme = readTheme();
|
|
265
|
+
// Upstream shipped a fixed dark palette; every role must instead come
|
|
266
|
+
// from the active preset, which resolves to Bloom's `rgb(...)` tokens.
|
|
267
|
+
for (const [role, value] of Object.entries(theme)) {
|
|
268
|
+
expect([role, value]).toEqual([role, expect.stringMatching(/^rgba?\(/)]);
|
|
269
|
+
}
|
|
270
|
+
expect(theme.activeTint).not.toBe('#FFFFFF');
|
|
271
|
+
expect(theme.activeTint).not.toBe(theme.inactiveTint);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it('paints the highlight with the resolved highlight token', () => {
|
|
275
|
+
const theme = readTheme();
|
|
276
|
+
const { UNSAFE_root } = renderWithTheme(<Bar activeIndex={0} />);
|
|
277
|
+
const painted = UNSAFE_root.findAll(
|
|
278
|
+
(node) => flattenStyle(node.props?.style).backgroundColor === theme.highlight,
|
|
279
|
+
);
|
|
280
|
+
expect(painted.length).toBeGreaterThan(0);
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it('applies a partial theme override without dropping the other roles', () => {
|
|
284
|
+
const defaults = readTheme();
|
|
285
|
+
const overridden = readTheme({ highlight: 'rgb(1 2 3)' });
|
|
286
|
+
expect(overridden.highlight).toBe('rgb(1 2 3)');
|
|
287
|
+
expect(overridden.activeTint).toBe(defaults.activeTint);
|
|
288
|
+
expect(overridden.glassTint).toBe(defaults.glassTint);
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it('never lets an explicit undefined in a partial punch a hole', () => {
|
|
292
|
+
const defaults = readTheme();
|
|
293
|
+
expect(readTheme({ activeTint: undefined }).activeTint).toBe(defaults.activeTint);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it('paints the bar with an overridden highlight', () => {
|
|
297
|
+
const { UNSAFE_root } = renderWithTheme(
|
|
298
|
+
<Bar activeIndex={0} theme={{ highlight: 'rgb(9 9 9)' }} />,
|
|
299
|
+
);
|
|
300
|
+
const painted = UNSAFE_root.findAll(
|
|
301
|
+
(node) => flattenStyle(node.props?.style).backgroundColor === 'rgb(9 9 9)',
|
|
302
|
+
);
|
|
303
|
+
expect(painted.length).toBeGreaterThan(0);
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
describe('native platform variants', () => {
|
|
308
|
+
it('falls back to the solid theme fill when liquid glass is unavailable', () => {
|
|
309
|
+
// The `expo-glass-effect` mock reports `isLiquidGlassAvailable() === false`
|
|
310
|
+
// (see the note in that file), so this is the branch every Android and
|
|
311
|
+
// pre-iOS-26 device takes.
|
|
312
|
+
const theme = readTheme();
|
|
313
|
+
const { UNSAFE_root } = renderWithTheme(
|
|
314
|
+
<NativeTabBarSurface theme={theme} style={{ borderRadius: 29 }} />,
|
|
315
|
+
);
|
|
316
|
+
expect(hosts(UNSAFE_root, 'GlassView')).toHaveLength(0);
|
|
317
|
+
const surface = hosts(UNSAFE_root, 'Animated.View')[0];
|
|
318
|
+
expect(flattenStyle(surface?.props.style).backgroundColor).toBe(theme.solidFallback);
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it('renders an SF Symbol on iOS when the item carries one', () => {
|
|
322
|
+
const theme = readTheme();
|
|
323
|
+
const item: TabBarItem = { ...(ITEMS[0] as TabBarItem), sfSymbol: 'house.fill' };
|
|
324
|
+
const { UNSAFE_root } = renderWithTheme(
|
|
325
|
+
<NativeTabBarGlyph item={item} tint={theme.activeTint} size={21} />,
|
|
326
|
+
);
|
|
327
|
+
const symbol = hosts(UNSAFE_root, 'SymbolView')[0];
|
|
328
|
+
expect(symbol?.props.name).toBe('house.fill');
|
|
329
|
+
expect(symbol?.props.tintColor).toBe(theme.activeTint);
|
|
330
|
+
expect(symbol?.props.size).toBe(21);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it('falls back to the item icon when no SF Symbol is given', () => {
|
|
334
|
+
const theme = readTheme();
|
|
335
|
+
const { queryByTestId, UNSAFE_root } = renderWithTheme(
|
|
336
|
+
<NativeTabBarGlyph item={ITEMS[0] as TabBarItem} tint={theme.activeTint} size={21} />,
|
|
337
|
+
);
|
|
338
|
+
expect(hosts(UNSAFE_root, 'SymbolView')).toHaveLength(0);
|
|
339
|
+
expect(queryByTestId('home-icon')).toBeTruthy();
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
});
|
|
@@ -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
|
+
});
|