Skip to content

Extend onScroll API #1854

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions examples/demos/Wrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { Menu, MenuOpen } from '@material-ui/icons';

interface Props {
title: string;
children: React.ReactChild;
isLoading?: boolean;
}

export default function Wrapper({ title, children }: Props) {
export default function Wrapper({ title, children, isLoading }: React.PropsWithChildren<Props>) {
const [isSidebarVisible, setIsSidebarVisible] = useState(true);

useLayoutEffect(() => {
Expand All @@ -17,11 +17,18 @@ export default function Wrapper({ title, children }: Props) {
}, [isSidebarVisible]);

return (
<div className="example">
<h1 onClick={() => setIsSidebarVisible(!isSidebarVisible)}>
{isSidebarVisible ? <MenuOpen /> : <Menu />} {title}
</h1>
{children}
</div>
<>
{isLoading && (
<div className="rdg-loading">
<div className="rdg-loading-text">Loading...</div>
</div>
)}
<div className="example">
<h1 onClick={() => setIsSidebarVisible(!isSidebarVisible)}>
{isSidebarVisible ? <MenuOpen /> : <Menu />} {title}
</h1>
{children}
</div>
</>
);
}
83 changes: 56 additions & 27 deletions examples/demos/example13-all-features.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import faker from 'faker';
import React, { useState, useMemo, useCallback, useRef } from 'react';
import React, { useCallback, useMemo, useRef, useState } from 'react';
import { AutoSizer } from 'react-virtualized';
import DataGrid, { Column, CellContent, SelectColumn, UpdateActions, DataGridHandle, GridRowsUpdatedEvent } from '../../src';

import DataGrid, { CellContent, Column, DataGridHandle, GridRowsUpdatedEvent, ScrollPosition, SelectColumn, UpdateActions } from '../../src';
import DropDownEditor from './components/Editors/DropDownEditor';
import ImageFormatter from './components/Formatters/ImageFormatter';
import Toolbar from './components/Toolbar/Toolbar';
Expand All @@ -28,6 +29,11 @@ faker.locale = 'en_GB';

const titles = ['Dr.', 'Mr.', 'Mrs.', 'Miss', 'Ms.'];

function isReachedBottom(event: React.UIEvent<HTMLDivElement>): boolean {
const target = event.target as HTMLDivElement;
return target.clientHeight + target.scrollTop === target.scrollHeight;
}

function createFakeRowObjectData(index: number): Row {
return {
id: `id_${index}`,
Expand All @@ -47,6 +53,18 @@ function createFakeRowObjectData(index: number): Row {
};
}

function loadMoreRows(newRowsCount: number, length: number): Promise<Row[]> {
return new Promise(resolve => {
const newRows: Row[] = [];

for (let i = 0; i < newRowsCount; i++) {
newRows[i] = createFakeRowObjectData(i + length);
}

setTimeout(() => resolve(newRows), 1000);
});
}

function createRows(numberOfRows: number): Row[] {
const rows: Row[] = [];

Expand All @@ -60,6 +78,7 @@ function createRows(numberOfRows: number): Row[] {
export default function AllFeaturesExample(): JSX.Element {
const [rows, setRows] = useState(() => createRows(2000));
const [selectedRows, setSelectedRows] = useState(() => new Set<string>());
const [isLoading, setIsLoading] = useState(false);
const gridRef = useRef<DataGridHandle>(null);

const columns: Column<Row>[] = useMemo(() => [
Expand Down Expand Up @@ -191,38 +210,48 @@ export default function AllFeaturesExample(): JSX.Element {

const handleAddRow = useCallback(({ newRowIndex }: { newRowIndex: number}): void => setRows([...rows, createFakeRowObjectData(newRowIndex)]), [rows]);

const handleScroll = useCallback(async (position: ScrollPosition, event: React.UIEvent<HTMLDivElement>) => {
if (!isReachedBottom(event)) return;

setIsLoading(true);

const newRows = await loadMoreRows(50, rows.length);

setRows([...rows, ...newRows]);
setIsLoading(false);
}, [rows]);

const getRowAt = useCallback((index: number): Row => rows[index], [rows]);

const getSize = useCallback((): number => rows.length, [rows.length]);

const onSelectedRowsChange = useCallback((newSelectedRows: Set<string>): void => setSelectedRows(newSelectedRows), []);

return (
<Wrapper title="All the features grid">
<>
<Toolbar onAddRow={handleAddRow} numberOfRows={rows.length} />
<div className="grid-autosizer-wrapper">
<AutoSizer>
{({ height, width }) => (
<DataGrid<Row, keyof Row>
ref={gridRef}
enableCellSelect
columns={columns}
rowGetter={getRowAt}
rowsCount={getSize()}
onGridRowsUpdated={handleGridRowsUpdated}
rowHeight={30}
minWidth={width}
minHeight={height}
selectedRows={selectedRows}
onSelectedRowsChange={onSelectedRowsChange}
enableCellCopyPaste
enableCellDragAndDrop
/>
)}
</AutoSizer>
</div>
</>
<Wrapper title="All the features grid" isLoading={isLoading}>
<Toolbar onAddRow={handleAddRow} numberOfRows={rows.length} />
<div className="grid-autosizer-wrapper">
<AutoSizer>
{({ height, width }) => (
<DataGrid<Row, keyof Row>
ref={gridRef}
enableCellSelect
columns={columns}
rowGetter={getRowAt}
rowsCount={getSize()}
onGridRowsUpdated={handleGridRowsUpdated}
rowHeight={30}
minWidth={width}
minHeight={height}
selectedRows={selectedRows}
onSelectedRowsChange={onSelectedRowsChange}
enableCellCopyPaste
enableCellDragAndDrop
onScroll={handleScroll}
/>
)}
</AutoSizer>
</div>
</Wrapper>
);
}
17 changes: 17 additions & 0 deletions examples/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,23 @@
.grid-autosizer-wrapper {
flex: 1 1 auto;
}

.rdg-loading {
position: fixed;
width: 100%;
height: 100%;
z-index: 9999;
background-color: rgba(0,0,0,0.75);
}

.rdg-loading .rdg-loading-text {
transform: translate(-50%, -50%);
top: 50%;
left: 50%;
position: absolute;
color: white;
font-size: 24px;
}
</style>
<script defer src="https://unpkg.com/core-js-bundle/minified.js"></script>
<script defer src="./index.js"></script>
Expand Down
4 changes: 2 additions & 2 deletions src/Canvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export interface CanvasProps<R, K extends keyof R> extends SharedDataGridProps<R
colOverscanEndIdx: number;
colVisibleStartIdx: number;
colVisibleEndIdx: number;
onScroll(position: ScrollPosition): void;
onScroll(position: ScrollPosition, event: React.UIEvent<HTMLDivElement>): void;
onCanvasKeydown?(e: React.KeyboardEvent<HTMLDivElement>): void;
onCanvasKeyup?(e: React.KeyboardEvent<HTMLDivElement>): void;
onRowSelectionChange(rowIdx: number, row: R, checked: boolean, isShiftClick: boolean): void;
Expand Down Expand Up @@ -98,7 +98,7 @@ function Canvas<R, K extends keyof R>({
function handleScroll(e: React.UIEvent<HTMLDivElement>) {
const { scrollLeft, scrollTop } = e.currentTarget;
setScrollTop(scrollTop);
onScroll({ scrollLeft, scrollTop });
onScroll({ scrollLeft, scrollTop }, e);
if (summaryRef.current) {
summaryRef.current.scrollLeft = scrollLeft;
}
Expand Down
6 changes: 3 additions & 3 deletions src/DataGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export interface DataGridProps<R, K extends keyof R> {
/** Function called whenever grid is sorted*/
onGridSort?(columnKey: keyof R, direction: DEFINE_SORT): void;
/** Called when the grid is scrolled */
onScroll?(scrollPosition: ScrollPosition): void;
onScroll?(scrollPosition: ScrollPosition, event: React.UIEvent<HTMLDivElement>): void;
/** Component used to render a draggable header cell */
draggableHeaderCell?: React.ComponentType<{ column: CalculatedColumn<R>; onHeaderDrop(): void }>;
RowsContainer?: React.ComponentType<RowsContainerProps>;
Expand Down Expand Up @@ -231,12 +231,12 @@ function DataGrid<R, K extends keyof R>({
props.onColumnResize?.(column.idx, width);
}

function handleScroll(scrollPosition: ScrollPosition) {
function handleScroll(scrollPosition: ScrollPosition, event: React.UIEvent<HTMLDivElement>) {
if (headerRef.current) {
headerRef.current.scrollLeft = scrollPosition.scrollLeft;
}
setScrollLeft(scrollPosition.scrollLeft);
props.onScroll?.(scrollPosition);
props.onScroll?.(scrollPosition, event);
}

function handleGridRowsUpdated(event: GridRowsUpdatedEvent<R>) {
Expand Down
1 change: 1 addition & 0 deletions style/rdg-core.less
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@
.rdg-grid {
// min-height is here to show the horizontal scrollbar when there are no rows
min-height: 1px;
margin-bottom: 8px;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this could break anything.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this doesn't break anything, and in fact this fixes a jumping issue that if the last row cells are editable, and when you click on it, the the drag square will push the rows above a little bit.

}