diff --git a/src/admin/select/SelectPhotosProvider.tsx b/src/admin/select/SelectPhotosProvider.tsx index 2a7c099b..ff608400 100644 --- a/src/admin/select/SelectPhotosProvider.tsx +++ b/src/admin/select/SelectPhotosProvider.tsx @@ -7,6 +7,7 @@ import { usePathname } from 'next/navigation'; import { useAppState } from '@/app/AppState'; import useClientSearchParams from '@/utility/useClientSearchParams'; import { pushPathWithEvent } from '@/utility/url'; +import { isElementPartiallyInViewport } from '@/utility/dom'; export const DATA_KEY_PHOTO_GRID = 'data-photo-grid'; @@ -28,10 +29,14 @@ export default function SelectPhotosProvider({ const [isPerformingSelectEdit, setIsPerformingSelectEdit] = useState(false); + const getPhotoGridElements = useCallback(() => + document.querySelectorAll(`[${DATA_KEY_PHOTO_GRID}]`) + , []); + useEffect(() => { - setCanCurrentPageSelectPhotos(document - .querySelector(`[${DATA_KEY_PHOTO_GRID}]`) !== null); - }, [pathname]); + const doesPageHavePhotoGrids = getPhotoGridElements().length > 0; + setCanCurrentPageSelectPhotos(doesPageHavePhotoGrids); + }, [pathname, getPhotoGridElements]); const isSelectingPhotos = useMemo(() => isUserSignedIn && @@ -50,10 +55,18 @@ export default function SelectPhotosProvider({ , [pathname]); useEffect(() => { - if (!isSelectingPhotos) { + if (isSelectingPhotos) { + const photoGrids = Array.from(getPhotoGridElements()); + const isSomePhotoGridVisible = photoGrids + .some(element => isElementPartiallyInViewport(element, -20)); + if (!isSomePhotoGridVisible) { + console.log('scrolling to photo grid'); + photoGrids[0]?.scrollIntoView({ behavior: 'smooth' }); + } + } else { setSelectedPhotoIds([]); } - }, [isSelectingPhotos]); + }, [isSelectingPhotos, getPhotoGridElements]); return ( { if (element) { const rect = element.getBoundingClientRect(); @@ -11,7 +11,8 @@ export const isElementEntirelyInViewport = ( document.documentElement.clientHeight ) && rect.right <= ( - window.innerWidth || document.documentElement.clientWidth + window.innerWidth || + document.documentElement.clientWidth ) ); } else { @@ -19,6 +20,28 @@ export const isElementEntirelyInViewport = ( } }; +export function isElementPartiallyInViewport( + element?: Element | null, + // Expand the viewport by `offset` pixels (negative offset = stricter) + offset = 0, +): boolean { + if (element) { + const rect = element.getBoundingClientRect(); + + const vh = window.innerHeight || document.documentElement.clientHeight; + const vw = window.innerWidth || document.documentElement.clientWidth; + + const topVisible = rect.bottom >= -offset; + const leftVisible = rect.right >= -offset; + const bottomVisible = rect.top <= vh + offset; + const rightVisible = rect.left <= vw + offset; + + return topVisible && leftVisible && bottomVisible && rightVisible; + } else { + return false; + } +} + export const clearGlobalFocus = () => { if (document.activeElement instanceof HTMLElement) { document.activeElement.blur();