From 4e508f02e1fe95fbf36fa2ad060036db464c25d4 Mon Sep 17 00:00:00 2001 From: mspivak-actionengine Date: Tue, 16 Jan 2024 19:18:46 +0300 Subject: [PATCH] fix(slider): scroll to a new item --- src/components/slider/slider.tsx | 94 ++++++++++++++++++----------- src/pages/comparison/comparison.tsx | 2 +- src/pages/debug-app/debug-app.tsx | 2 +- src/pages/viewer-app/viewer-app.tsx | 2 +- 4 files changed, 62 insertions(+), 38 deletions(-) diff --git a/src/components/slider/slider.tsx b/src/components/slider/slider.tsx index 49db9d39..a82fd267 100644 --- a/src/components/slider/slider.tsx +++ b/src/components/slider/slider.tsx @@ -1,4 +1,4 @@ -import { useRef } from "react"; +import { useRef, useEffect } from "react"; import styled, { css } from "styled-components"; import ChevronIcon from "../../../public/icons/chevron.svg"; import { SliderListItem } from "./slider-list-item"; @@ -94,9 +94,6 @@ type SliderProps = { onDelete?: (id: string) => void; }; -const BOOKMARKS_OFFSET = 150; -const OFFSET = 54; - export const Slider = ({ data, editingMode, @@ -114,57 +111,84 @@ export const Slider = ({ } }; - const disableLeftArrow = selectedItemId === data[0]?.id || !selectedItemId; - const disableRightArrow = - selectedItemId === data[data.length - 1]?.id || !selectedItemId; - - const isBookmarkSlider = sliderType === SliderType.Bookmarks; - const isPhaseSlider = sliderType === SliderType.Phase; - const isFloorsSlider = sliderType === SliderType.Floors; - - const layout = useAppLayout(); - const handleLeftArrowClick = () => { const currentSelectedIndex = data.findIndex( (item) => item.id === selectedItemId ); - const prevItemId = data[currentSelectedIndex - 1].id; - onSelect(prevItemId); - - sliderItemsListRef?.current?.scrollBy({ - top: isFloorsSlider ? OFFSET : 0, - left: isBookmarkSlider ? -BOOKMARKS_OFFSET : isPhaseSlider ? -OFFSET : 0, - behavior: "smooth", - }); + const prevItemId = data[currentSelectedIndex - 1]?.id; + onSelectHandler(prevItemId); }; const handleRightArrowClick = () => { const currentSelectedIndex = data.findIndex( (item) => item.id === selectedItemId ); - const nextItemId = data[currentSelectedIndex + 1].id; - onSelect(nextItemId); - - sliderItemsListRef?.current?.scrollBy({ - top: isFloorsSlider ? -OFFSET : 0, - left: isBookmarkSlider ? BOOKMARKS_OFFSET : isPhaseSlider ? OFFSET : 0, - behavior: "smooth", - }); + const nextItemId = data[currentSelectedIndex + 1]?.id; + onSelectHandler(nextItemId); }; const onSelectHandler = (id: string): void => { - onSelect(id); + if (id) { + scrollItemIntoView(id); + onSelect(id); + } + }; + + const isItemVisible = (item: HTMLDivElement | undefined): boolean => { + const listElement = sliderItemsListRef?.current; + if (!item || !listElement) { + return false; + } + const listLeft = listElement.offsetLeft; + const listTop = listElement.offsetTop; + const listRight = listLeft + listElement.offsetWidth; + const listBottom = listTop + listElement.offsetHeight; + + const itemLeft = item.offsetLeft - listElement.scrollLeft; + const itemTop = item.offsetTop - listElement.scrollTop; + const itemRight = itemLeft + item.offsetWidth; + const itemBottom = itemTop + item.offsetHeight; + + const isVisible = + itemLeft >= listLeft && + itemRight <= listRight && + itemTop >= listTop && + itemBottom <= listBottom; + return isVisible; + }; + + const scrollItemIntoView = (id: string): void => { + if (!id) { + return; + } const listItem = listItems.current?.find( (item: HTMLDivElement) => item.id === id ); - if (isBookmarkSlider || isPhaseSlider) { - listItem?.scrollIntoView({ behavior: "smooth", inline: "center" }); - } else { - listItem?.scrollIntoView({ behavior: "smooth", block: "center" }); + const isVisible = isItemVisible(listItem); + if (!isVisible) { + if (isBookmarkSlider || isPhaseSlider) { + listItem?.scrollIntoView({ behavior: "smooth", inline: "nearest" }); + } else { + listItem?.scrollIntoView({ behavior: "smooth", block: "nearest" }); + } } }; + useEffect(() => { + scrollItemIntoView(selectedItemId); + }, [selectedItemId]); + + const disableLeftArrow = selectedItemId === data[0]?.id || !selectedItemId; + const disableRightArrow = + selectedItemId === data[data.length - 1]?.id || !selectedItemId; + + const isBookmarkSlider = sliderType === SliderType.Bookmarks; + const isPhaseSlider = sliderType === SliderType.Phase; + const isFloorsSlider = sliderType === SliderType.Floors; + + const layout = useAppLayout(); + return ( <> { const addBookmarkHandler = () => { const newBookmarkId = uuidv4(); - setSelectedBookmarkId(newBookmarkId); makeScreenshot().then((imageUrl) => { setBookmarks((prev) => [ ...prev, @@ -380,6 +379,7 @@ export const Comparison = ({ mode }: ComparisonPageProps) => { activeLayersIdsRightSide: [...activeLayersIdsRightSide], }, ]); + setSelectedBookmarkId(newBookmarkId); }); }; diff --git a/src/pages/debug-app/debug-app.tsx b/src/pages/debug-app/debug-app.tsx index 9bcbe2ee..235978da 100644 --- a/src/pages/debug-app/debug-app.tsx +++ b/src/pages/debug-app/debug-app.tsx @@ -567,7 +567,6 @@ export const DebugApp = () => { const addBookmarkHandler = () => { const newBookmarkId = uuidv4(); - setSelectedBookmarkId(newBookmarkId); makeScreenshot().then((imageUrl) => { setBookmarks((prev) => [ ...prev, @@ -583,6 +582,7 @@ export const DebugApp = () => { activeLayersIdsRightSide: [], }, ]); + setSelectedBookmarkId(newBookmarkId); }); }; diff --git a/src/pages/viewer-app/viewer-app.tsx b/src/pages/viewer-app/viewer-app.tsx index 9c5049dd..c2525e0c 100644 --- a/src/pages/viewer-app/viewer-app.tsx +++ b/src/pages/viewer-app/viewer-app.tsx @@ -437,7 +437,6 @@ export const ViewerApp = () => { const addBookmarkHandler = () => { const newBookmarkId = uuidv4(); - setSelectedBookmarkId(newBookmarkId); makeScreenshot().then((imageUrl) => { setBookmarks((prev) => [ ...prev, @@ -452,6 +451,7 @@ export const ViewerApp = () => { activeLayersIdsRightSide: [], }, ]); + setSelectedBookmarkId(newBookmarkId); }); };