diff --git a/packages/client/src/pages/Home/Section/Body/index.js b/packages/client/src/pages/Home/Section/Body/index.js index 5c5063ad2d..0b1bb063ae 100644 --- a/packages/client/src/pages/Home/Section/Body/index.js +++ b/packages/client/src/pages/Home/Section/Body/index.js @@ -35,7 +35,13 @@ import EmptyContainer from "../../../../components/EmptyContainer"; import withLoader from "../../../../HOCs/withLoader"; import TableView from "./TableView/TableContainer"; import withHotkeys from "../../../../HOCs/withHotkeys"; -import { Consumer, isMobile, isTablet } from "@docspace/shared/utils"; +import { + clearEdgeScrollingTimer, + Consumer, + isMobile, + isTablet, + onEdgeScrolling, +} from "@docspace/shared/utils"; import { isElementInViewport } from "@docspace/shared/utils/common"; import { DeviceType } from "@docspace/shared/enums"; @@ -197,6 +203,7 @@ const SectionBodyContent = (props) => { setDragging(true); } + onEdgeScrolling(e); setTooltipPosition(e.pageX, e.pageY); const wrapperElement = document.elementFromPoint(e.clientX, e.clientY); if (!wrapperElement) { @@ -240,6 +247,7 @@ const SectionBodyContent = (props) => { }; const onMouseUp = (e) => { + clearEdgeScrollingTimer(); setStartDrag(false); setTimeout(() => { diff --git a/packages/shared/components/selection-area/SelectionArea.tsx b/packages/shared/components/selection-area/SelectionArea.tsx index c56dc86352..12df35c65b 100644 --- a/packages/shared/components/selection-area/SelectionArea.tsx +++ b/packages/shared/components/selection-area/SelectionArea.tsx @@ -30,6 +30,7 @@ import { useTheme } from "styled-components"; import { StyledSelectionArea } from "./SelectionArea.styled"; import { frames } from "./SelectionArea.utils"; import { SelectionAreaProps, TArrayTypes } from "./SelectionArea.types"; +import { onEdgeScrolling, clearEdgeScrollingTimer } from "../../utils"; const SelectionArea = ({ onMove, @@ -298,6 +299,8 @@ const SelectionArea = ({ areaLocation.current.x2 = e.clientX; areaLocation.current.y2 = e.clientY; + onEdgeScrolling(e); + frame().next(); }, [frame], @@ -358,6 +361,7 @@ const SelectionArea = ({ }, [onMoveAction, onScroll, onTapMove]); const onTapStop = React.useCallback(() => { + clearEdgeScrollingTimer(); removeListeners(); document.removeEventListener("mouseup", onTapStop); window.removeEventListener("blur", onTapStop); diff --git a/packages/shared/utils/edgeScrolling.ts b/packages/shared/utils/edgeScrolling.ts new file mode 100644 index 0000000000..09f338624c --- /dev/null +++ b/packages/shared/utils/edgeScrolling.ts @@ -0,0 +1,62 @@ +const edgeSize = 200; +const maxStep = 50; + +let timer: null | ReturnType = null; + +export const clearEdgeScrollingTimer = () => { + if (timer) clearTimeout(timer); +}; + +export const onEdgeScrolling = (e: React.MouseEvent) => { + const bodyScroll = document.querySelector(".section-scroll"); + + if (bodyScroll) { + const viewportY = e.clientY; + const viewportHeight = document.documentElement.clientHeight; + const edgeTop = edgeSize; + const edgeBottom = viewportHeight - edgeSize; + const isInTopEdge = viewportY < edgeTop; + const isInBottomEdge = viewportY > edgeBottom; + + if (!(isInTopEdge || isInBottomEdge)) { + clearEdgeScrollingTimer(); + return; + } + + const maxScrollY = bodyScroll.scrollHeight - viewportHeight; + + const adjustWindowScroll = () => { + const currentScrollY = bodyScroll.scrollTop; + + const canScrollUp = currentScrollY > 0; + const canScrollDown = currentScrollY < maxScrollY; + let nextScrollY = currentScrollY; + + if (isInTopEdge && canScrollUp) { + const intensity = (edgeTop - viewportY) / edgeSize; + nextScrollY -= maxStep * intensity; + } else if (isInBottomEdge && canScrollDown) { + const intensity = (viewportY - edgeBottom) / edgeSize; + + nextScrollY += maxStep * intensity; + } + + nextScrollY = Math.max(0, Math.min(maxScrollY, nextScrollY)); + + if (nextScrollY !== currentScrollY) { + bodyScroll.scrollTo(0, nextScrollY); + return true; + } + return false; + }; + + const checkForWindowScroll = () => { + clearEdgeScrollingTimer(); + if (adjustWindowScroll()) { + timer = setTimeout(checkForWindowScroll, 30); + } + }; + + checkForWindowScroll(); + } +}; diff --git a/packages/shared/utils/index.ts b/packages/shared/utils/index.ts index cab623a058..6f4d74fba9 100644 --- a/packages/shared/utils/index.ts +++ b/packages/shared/utils/index.ts @@ -77,6 +77,7 @@ import { } from "./common"; import { DeviceType } from "../enums"; import { TFile } from "../api/files/types"; +import { onEdgeScrolling, clearEdgeScrollingTimer } from "./edgeScrolling"; export { isBetaLanguage, @@ -127,6 +128,8 @@ export { ObjectUtils, getLogoUrl, isMobileDevice, + onEdgeScrolling, + clearEdgeScrollingTimer, }; export const getModalType = () => {