Skip to content

Commit

Permalink
Add spacerElement prop
Browse files Browse the repository at this point in the history
  • Loading branch information
oleggrishechkin committed Oct 25, 2022
1 parent c8fd848 commit 7302dd0
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 20 deletions.
33 changes: 17 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,22 +68,23 @@ Try 100k list [demo](https://codesandbox.io/s/react-viewport-list-xw2rt)

## Props

| name | type | default | description |
|---------------------------|-----------------------------------------------------------------------------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `viewportRef` | MutableRefObject\<HTMLElement or null\> or RefObject\<HTMLElement or null\> | required | Viewport and scroll container.<br>`document.documentElement` will be used if `viewportRef` not provided. |
| `items` | T[] | [] | Array of items. |
| `itemMinSize` | number | 0 | Item average (estimated) size (`height` for `axis="y"` and `width` for `axis="x"`) in px.<br>Size should be greater or equal zero.<br>Size will be computed automatically if `itemMinSize` not provided or equal zero. |
| `margin` | number | -1 | Item margin (`margin-bottom` for `axis="y"` and `margin-right` for `axis="x"`) in px.<br>Margin should be greater or equal -1.<br>Margin will be computed automatically if `margin` not provided or equal -1.<br>You should still set margin in item styles |
| `overscan` | number | 1 | Count of "overscan" items. |
| `axis` | "y" / "x" | 'y' | Scroll axis:<ul><li>"y" - vertical</li><li>"x" - horizontal</li></ul> |
| `initialIndex` | number | -1 | Initial item index in viewport. |
| `initialAlignToTop` | boolean or ScrollIntoViewOptions | true | [scrollIntoView](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView) param.<br>Used with `initialIndex` |
| `initialOffset` | number | 0 | Offset after `scrollIntoView` call.<br>Used with `initialIndex`.<br>This value will be added to the scroll after scroll to index. |
| `children` | (item: T, index: number, array: T[]) => ReactNode | required | Item render function.<br>Similar to [`Array.Prototype.map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map). |
| `onViewportIndexesChange` | (viewportIndexes: [number, number]) => void | optional | Will be called on rendered in viewport indexes change. |
| `overflowAnchor` | "none" / "auto" | "auto" | Compatibility for `overflow-anchor: none`.<br>Set it to "none" if you use `overflow-anchor: none` in your parent container styles. |
| `withCache` | boolean | true | Cache rendered item heights. |
| `scrollThreshold` | number | 0 | If scroll diff more than `scrollThreshold` setting indexes was skipped. It's can be useful for better fast scroll UX. |
| name | type | default | description |
|---------------------------|--------------------------------------------------------------------------------------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `viewportRef` | MutableRefObject\<HTMLElement or null\> or RefObject\<HTMLElement or null\> | required | Viewport and scroll container.<br>`document.documentElement` will be used if `viewportRef` not provided. |
| `items` | T[] | [] | Array of items. |
| `itemMinSize` | number | 0 | Item average (estimated) size (`height` for `axis="y"` and `width` for `axis="x"`) in px.<br>Size should be greater or equal zero.<br>Size will be computed automatically if `itemMinSize` not provided or equal zero. |
| `margin` | number | -1 | Item margin (`margin-bottom` for `axis="y"` and `margin-right` for `axis="x"`) in px.<br>Margin should be greater or equal -1.<br>Margin will be computed automatically if `margin` not provided or equal -1.<br>You should still set margin in item styles |
| `overscan` | number | 1 | Count of "overscan" items. |
| `axis` | "y" / "x" | 'y' | Scroll axis:<ul><li>"y" - vertical</li><li>"x" - horizontal</li></ul> |
| `initialIndex` | number | -1 | Initial item index in viewport. |
| `initialAlignToTop` | boolean or ScrollIntoViewOptions | true | [scrollIntoView](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView) param.<br>Used with `initialIndex` |
| `initialOffset` | number | 0 | Offset after `scrollIntoView` call.<br>Used with `initialIndex`.<br>This value will be added to the scroll after scroll to index. |
| `children` | (item: T, index: number, array: T[]) => ReactNode | required | Item render function.<br>Similar to [`Array.Prototype.map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map). |
| `onViewportIndexesChange` | (viewportIndexes: [number, number]) => void | optional | Will be called on rendered in viewport indexes change. |
| `overflowAnchor` | "none" / "auto" | "auto" | Compatibility for `overflow-anchor: none`.<br>Set it to "none" if you use `overflow-anchor: none` in your parent container styles. |
| `withCache` | boolean | true | Cache rendered item heights. |
| `scrollThreshold` | number | 0 | If scroll diff more than `scrollThreshold` setting indexes was skipped. It's can be useful for better fast scroll UX. |
| `spocerElement` | keyof JSX.IntrinsicElements | "div" | If some rare cases you should use specific elements instead of div for spacers |

## Methods

Expand Down
11 changes: 7 additions & 4 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
forwardRef,
ForwardedRef,
RefObject,
createElement,
} from 'react';

const IS_SSR = typeof window === 'undefined';
Expand Down Expand Up @@ -121,6 +122,7 @@ export interface ViewportListProps<T> {
overflowAnchor?: 'none' | 'auto';
withCache?: boolean;
scrollThreshold?: number;
spacerElement?: keyof JSX.IntrinsicElements;
}

const getDiff = (value1: number, value2: number, step: number) => Math.ceil(Math.abs(value1 - value2) / step);
Expand All @@ -141,6 +143,7 @@ const ViewportListInner = <T,>(
overflowAnchor = 'auto',
withCache = true,
scrollThreshold = 0,
spacerElement = 'div',
}: ViewportListProps<T>,
ref: ForwardedRef<ViewportListRef>,
) => {
Expand All @@ -155,8 +158,8 @@ const ViewportListInner = <T,>(
const [indexes, setIndexes] = useState([initialIndex, initialIndex]);
const startIndex = (indexes[0] = normalizeValue(0, indexes[0], maxIndex));
const endIndex = (indexes[1] = normalizeValue(startIndex, indexes[1], maxIndex));
const topSpacerRef = useRef<HTMLDivElement>(null);
const bottomSpacerRef = useRef<HTMLDivElement>(null);
const topSpacerRef = useRef<any>(null);
const bottomSpacerRef = useRef<any>(null);
const cacheRef = useRef<number[]>([]);
const scrollToIndexRef = useRef<{
index: number;
Expand Down Expand Up @@ -562,9 +565,9 @@ const ViewportListInner = <T,>(

return (
<Fragment>
<div ref={topSpacerRef} style={topSpacerStyle} />
{createElement(spacerElement, { ref: topSpacerRef, style: topSpacerStyle })}
{items.slice(startIndex, endIndex + 1).map((item, index) => children(item, startIndex + index, items))}
<div ref={bottomSpacerRef} style={bottomSpacerStyle} />
{createElement(spacerElement, { ref: bottomSpacerRef, style: bottomSpacerStyle })}
</Fragment>
);
};
Expand Down

0 comments on commit 7302dd0

Please sign in to comment.