diff --git a/.size-limit.json b/.size-limit.json index 58bd4d38b..8ff941c58 100644 --- a/.size-limit.json +++ b/.size-limit.json @@ -3,7 +3,7 @@ "name": "Total", "path": "lib/index.mjs", "import": "*", - "limit": "5.25 kB" + "limit": "5.20 kB" }, { "name": "VList", diff --git a/src/core/scroller.ts b/src/core/scroller.ts index 973603fd2..a3a6e7584 100644 --- a/src/core/scroller.ts +++ b/src/core/scroller.ts @@ -7,7 +7,6 @@ import { ACTION_SCROLL_END, UPDATE_SIZE, ACTION_MANUAL_SCROLL, - SCROLL_IDLE, } from "./store"; import { ScrollToIndexAlign } from "./types"; import { debounce, throttle, timeout, clamp } from "./utils"; @@ -20,7 +19,7 @@ const createOnWheel = ( onScrollStopped: () => void ) => { return throttle((e: WheelEvent) => { - if (store._getScrollDirection() === SCROLL_IDLE) { + if (!store._getIsScrolling()) { // Scroll start should be detected with scroll event return; } diff --git a/src/core/store.ts b/src/core/store.ts index 42f0cb918..0eae55518 100644 --- a/src/core/store.ts +++ b/src/core/store.ts @@ -39,7 +39,7 @@ const SUBPIXEL_THRESHOLD = 1.5; // 0.5 * 3 export const SCROLL_IDLE = 0; export const SCROLL_DOWN = 1; export const SCROLL_UP = 2; -export type ScrollDirection = +type ScrollDirection = | typeof SCROLL_IDLE | typeof SCROLL_DOWN | typeof SCROLL_UP; @@ -69,7 +69,7 @@ type Subscriber = () => void; export const UPDATE_SCROLL = 0b00001; export const UPDATE_SIZE = 0b00010; export const UPDATE_JUMP = 0b00100; -export const UPDATE_SCROLL_DIRECTION = 0b01000; +export const UPDATE_IS_SCROLLING = 0b01000; export const UPDATE_SCROLL_WITH_EVENT = 0b10000; export type VirtualStore = { @@ -82,7 +82,7 @@ export type VirtualStore = { _getItemsLength(): number; _getScrollOffset(): number; _getScrollOffsetMax(): number; - _getScrollDirection(): ScrollDirection; + _getIsScrolling(): boolean; _getViewportSize(): number; _getCorrectedScrollSize(): number; _getJumpCount(): number; @@ -122,8 +122,12 @@ export const createVirtualStore = ( const updateScrollDirection = (dir: ScrollDirection): boolean => { const prev = _scrollDirection; _scrollDirection = dir; + // Return true if scrolling is just started or stopped - return _scrollDirection !== prev; + return ( + _scrollDirection !== prev && + (_scrollDirection === SCROLL_IDLE || prev === SCROLL_IDLE) + ); }; return { @@ -179,8 +183,8 @@ export const createVirtualStore = ( return scrollOffset; }, _getScrollOffsetMax: getScrollOffsetMax, - _getScrollDirection() { - return _scrollDirection; + _getIsScrolling() { + return _scrollDirection !== SCROLL_IDLE; }, _getViewportSize() { return viewportSize; @@ -321,7 +325,7 @@ export const createVirtualStore = ( !_isManualScrolling ) { if (updateScrollDirection(delta < 0 ? SCROLL_UP : SCROLL_DOWN)) { - mutated += UPDATE_SCROLL_DIRECTION; + mutated += UPDATE_IS_SCROLLING; } } @@ -344,7 +348,7 @@ export const createVirtualStore = ( } case ACTION_SCROLL_END: { if (updateScrollDirection(SCROLL_IDLE)) { - mutated = UPDATE_SCROLL_DIRECTION; + mutated = UPDATE_IS_SCROLLING; } _isShifting = _isManualScrolling = false; break; diff --git a/src/react/VGrid.tsx b/src/react/VGrid.tsx index 912722adf..005ce8b10 100644 --- a/src/react/VGrid.tsx +++ b/src/react/VGrid.tsx @@ -10,24 +10,18 @@ import { } from "react"; import { ACTION_ITEMS_LENGTH_CHANGE, - UPDATE_SCROLL_DIRECTION, + UPDATE_IS_SCROLLING, UPDATE_JUMP, UPDATE_SCROLL, UPDATE_SIZE, VirtualStore, createVirtualStore, - SCROLL_IDLE, } from "../core/store"; import { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect"; import { useSelector } from "./useSelector"; -import { values } from "../core/utils"; +import { max, min, values } from "../core/utils"; import { createScroller } from "../core/scroller"; -import { - clampEndIndex, - clampStartIndex, - emptyComponents, - refKey, -} from "./utils"; +import { emptyComponents, refKey } from "./utils"; import { useStatic } from "./useStatic"; import { CustomViewportComponent, @@ -321,15 +315,15 @@ export const VGrid = forwardRef( hStore._getRange, UPDATE_SCROLL + UPDATE_SIZE ); - const vScrollDirection = useSelector( + const verticalScrolling = useSelector( vStore, - vStore._getScrollDirection, - UPDATE_SCROLL_DIRECTION + vStore._getIsScrolling, + UPDATE_IS_SCROLLING ); - const hScrollDirection = useSelector( + const horizontalScrolling = useSelector( hStore, - hStore._getScrollDirection, - UPDATE_SCROLL_DIRECTION + hStore._getIsScrolling, + UPDATE_IS_SCROLLING ); const vJumpCount = useSelector(vStore, vStore._getJumpCount, UPDATE_JUMP); const hJumpCount = useSelector(hStore, hStore._getJumpCount, UPDATE_JUMP); @@ -346,8 +340,6 @@ export const VGrid = forwardRef( true ); const rootRef = useRef(null); - const vScrolling = vScrollDirection !== SCROLL_IDLE; - const hScrolling = hScrollDirection !== SCROLL_IDLE; useIsomorphicLayoutEffect(() => { const root = rootRef[refKey]!; @@ -421,29 +413,10 @@ export const VGrid = forwardRef( }; }, [children]); - const overscanedStartRowIndex = clampStartIndex( - startRowIndex, - overscan, - vScrollDirection - ); - const overscanedEndRowIndex = clampEndIndex( - endRowIndex, - overscan, - vScrollDirection, - rowCount - ); - const overscanedStartColIndex = clampStartIndex( - startColIndex, - overscan, - hScrollDirection - ); - const overscanedEndColIndex = clampEndIndex( - endColIndex, - overscan, - hScrollDirection, - colCount - ); - + const overscanedStartRowIndex = max(startRowIndex - overscan, 0); + const overscanedEndRowIndex = min(endRowIndex + overscan, rowCount - 1); + const overscanedStartColIndex = max(startColIndex - overscan, 0); + const overscanedEndColIndex = min(endColIndex + overscan, colCount - 1); const items = useMemo(() => { const res: ReactElement[] = []; for (let i = overscanedStartRowIndex; i <= overscanedEndRowIndex; i++) { @@ -478,7 +451,7 @@ export const VGrid = forwardRef( ref={rootRef} width={width} height={height} - scrolling={vScrolling || hScrolling} + scrolling={verticalScrolling || horizontalScrolling} attrs={useMemo( () => ({ ...viewportAttrs, diff --git a/src/react/VList.tsx b/src/react/VList.tsx index 74441a350..45de91aae 100644 --- a/src/react/VList.tsx +++ b/src/react/VList.tsx @@ -13,22 +13,14 @@ import { createVirtualStore, UPDATE_SIZE, UPDATE_JUMP, - UPDATE_SCROLL_DIRECTION, + UPDATE_IS_SCROLLING, UPDATE_SCROLL, - SCROLL_IDLE, } from "../core/store"; import { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect"; import { useSelector } from "./useSelector"; -import { exists, values } from "../core/utils"; +import { exists, max, min, values } from "../core/utils"; import { createScroller } from "../core/scroller"; -import { - MayHaveKey, - clampEndIndex, - clampStartIndex, - emptyComponents, - flattenChildren, - refKey, -} from "./utils"; +import { MayHaveKey, emptyComponents, flattenChildren, refKey } from "./utils"; import { useStatic } from "./useStatic"; import { useLatestRef } from "./useLatestRef"; import { createResizer } from "../core/resizer"; @@ -235,10 +227,10 @@ export const VList = forwardRef( store._getRange, UPDATE_SCROLL + UPDATE_SIZE ); - const scrollDirection = useSelector( + const scrolling = useSelector( store, - store._getScrollDirection, - UPDATE_SCROLL_DIRECTION + store._getIsScrolling, + UPDATE_IS_SCROLLING ); const jumpCount = useSelector(store, store._getJumpCount, UPDATE_JUMP); const scrollSize = useSelector( @@ -248,7 +240,6 @@ export const VList = forwardRef( true ); const rootRef = useRef(null); - const scrolling = scrollDirection !== SCROLL_IDLE; useIsomorphicLayoutEffect(() => { const root = rootRef[refKey]!; @@ -307,17 +298,8 @@ export const VList = forwardRef( [] ); - const overscanedStartIndex = clampStartIndex( - startIndex, - overscan, - scrollDirection - ); - const overscanedEndIndex = clampEndIndex( - endIndex, - overscan, - scrollDirection, - count - ); + const overscanedStartIndex = max(startIndex - overscan, 0); + const overscanedEndIndex = min(endIndex + overscan, count - 1); const items = useMemo(() => { const res: ReactElement[] = []; for (let i = overscanedStartIndex; i <= overscanedEndIndex; i++) { diff --git a/src/react/WVList.tsx b/src/react/WVList.tsx index 18789172b..af4a1ec49 100644 --- a/src/react/WVList.tsx +++ b/src/react/WVList.tsx @@ -9,25 +9,17 @@ import { } from "react"; import { ACTION_ITEMS_LENGTH_CHANGE, - UPDATE_SCROLL_DIRECTION, + UPDATE_IS_SCROLLING, UPDATE_JUMP, UPDATE_SCROLL, UPDATE_SIZE, createVirtualStore, - SCROLL_IDLE, } from "../core/store"; import { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect"; import { useSelector } from "./useSelector"; -import { exists, values } from "../core/utils"; +import { exists, max, min, values } from "../core/utils"; import { createWindowScroller } from "../core/scroller"; -import { - MayHaveKey, - clampEndIndex, - clampStartIndex, - emptyComponents, - flattenChildren, - refKey, -} from "./utils"; +import { MayHaveKey, emptyComponents, flattenChildren, refKey } from "./utils"; import { useStatic } from "./useStatic"; import { useLatestRef } from "./useLatestRef"; import { createWindowResizer } from "../core/resizer"; @@ -181,10 +173,10 @@ export const WVList = forwardRef( store._getRange, UPDATE_SCROLL + UPDATE_SIZE ); - const scrollDirection = useSelector( + const scrolling = useSelector( store, - store._getScrollDirection, - UPDATE_SCROLL_DIRECTION + store._getIsScrolling, + UPDATE_IS_SCROLLING ); const jumpCount = useSelector(store, store._getJumpCount, UPDATE_JUMP); const scrollSize = useSelector( @@ -194,7 +186,6 @@ export const WVList = forwardRef( true ); const rootRef = useRef(null); - const scrolling = scrollDirection !== SCROLL_IDLE; useIsomorphicLayoutEffect(() => { const root = rootRef[refKey]!; @@ -237,17 +228,8 @@ export const WVList = forwardRef( [] ); - const overscanedStartIndex = clampStartIndex( - startIndex, - overscan, - scrollDirection - ); - const overscanedEndIndex = clampEndIndex( - endIndex, - overscan, - scrollDirection, - count - ); + const overscanedStartIndex = max(startIndex - overscan, 0); + const overscanedEndIndex = min(endIndex + overscan, count - 1); const items = useMemo(() => { const res: ReactElement[] = []; for (let i = overscanedStartIndex; i <= overscanedEndIndex; i++) { diff --git a/src/react/utils.ts b/src/react/utils.ts index 5e3e8652f..c6c9d96a0 100644 --- a/src/react/utils.ts +++ b/src/react/utils.ts @@ -1,6 +1,5 @@ import { ReactElement, ReactFragment, ReactNode } from "react"; -import { exists, max, min, isArray } from "../core/utils"; -import { SCROLL_DOWN, SCROLL_UP, ScrollDirection } from "../core/store"; +import { exists, isArray } from "../core/utils"; export const refKey = "current"; @@ -36,26 +35,3 @@ export const flattenChildren = (children: ReactNode): ItemElement[] => { }; export type MayHaveKey = { key?: React.Key }; - -export const clampStartIndex = ( - startIndex: number, - overscan: number, - scrollDirection: ScrollDirection -): number => { - return max( - startIndex - (scrollDirection === SCROLL_DOWN ? 1 : max(1, overscan)), - 0 - ); -}; - -export const clampEndIndex = ( - endIndex: number, - overscan: number, - scrollDirection: ScrollDirection, - count: number -): number => { - return min( - endIndex + (scrollDirection === SCROLL_UP ? 1 : max(1, overscan)), - count - 1 - ); -};