Created
April 8, 2026 06:38
-
-
Save khasky/c00c1073c3466129c0ee510d70b6f786 to your computer and use it in GitHub Desktop.
useDirectionTransform React Hook
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Builds Theme UI `sx` transforms so a sticky/floating bar slides in on scroll-up or near the top | |
| // and slides away on scroll-down; optional burger-menu attrs keep it visible while the menu is open. | |
| import React from 'react'; | |
| import { BoxProps } from 'theme-ui'; | |
| import { useScrollDirection, ScrollDirection } from '@/hooks/useScrollDirection'; | |
| const SCROLL_Y_OFFSET_PX = 500; | |
| interface DirectionTransformProps { | |
| fromBottom?: boolean; | |
| translateTop?: number; | |
| translateBottom?: number; | |
| minOffset?: number; | |
| burgerMenuElementId?: string; | |
| burgerMenuOpenAttr?: string; | |
| } | |
| export function useDirectionTransform({ | |
| fromBottom = false, | |
| translateTop = 100, | |
| translateBottom = 0, | |
| minOffset = SCROLL_Y_OFFSET_PX, | |
| burgerMenuElementId, | |
| burgerMenuOpenAttr, | |
| }: DirectionTransformProps) { | |
| const [isVisible, setIsVisible] = React.useState(false); | |
| const direction = useScrollDirection(); | |
| const styles: BoxProps['sx'] = {}; | |
| const checkIsMenuOpen = () => { | |
| if (typeof window !== 'undefined' && burgerMenuElementId && burgerMenuOpenAttr) { | |
| const menuButton = document.querySelector('#' + burgerMenuElementId); | |
| const isMenuOpen = menuButton | |
| ? menuButton.getAttribute(burgerMenuOpenAttr) === 'true' | |
| : false; | |
| return isMenuOpen; | |
| } | |
| return false; | |
| }; | |
| if ( | |
| checkIsMenuOpen() || | |
| direction === ScrollDirection.Initial || | |
| direction === ScrollDirection.Top | |
| ) { | |
| styles.transform = fromBottom | |
| ? `translateY(${translateTop}%)` | |
| : `translateY(${translateBottom})`; | |
| } else if (direction === ScrollDirection.Bottom) { | |
| styles.transform = fromBottom | |
| ? `translateY(${translateBottom}%)` | |
| : `translateY(-${translateTop}%)`; | |
| } | |
| React.useEffect(() => { | |
| const toggleVisibility = () => setIsVisible(window.scrollY > minOffset); | |
| window.addEventListener('scroll', toggleVisibility); | |
| return () => window.removeEventListener('scroll', toggleVisibility); | |
| }, []); | |
| return { styles, isVisible }; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment