Skip to content

Commit

Permalink
feat: replaced react-window by tanstack/react-virtual
Browse files Browse the repository at this point in the history
  • Loading branch information
gpuente committed Jul 1, 2024
1 parent 4966b55 commit 7e9b024
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 100 deletions.
72 changes: 28 additions & 44 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@
"@total-typescript/ts-reset": "^0.5.1",
"@types/react": "^18.2.79",
"@types/react-dom": "^18.2.18",
"@types/react-window": "^1.8.8",
"@types/uuid": "^9.0.7",
"@types/wicg-file-system-access": "^2020.9.6",
"@typescript-eslint/eslint-plugin": "^6.18.1",
Expand Down Expand Up @@ -96,6 +95,7 @@
"dependencies": {
"@powerhousedao/design-system": "1.0.0-alpha.141",
"@sentry/react": "^7.109.0",
"@tanstack/react-virtual": "^3.8.1",
"did-key-creator": "^1.2.0",
"document-drive": "1.0.0-alpha.80",
"document-model": "1.7.0",
Expand All @@ -113,8 +113,6 @@
"react-i18next": "^13.5.0",
"react-router-dom": "^6.11.2",
"react-stately": "^3.31.0",
"react-virtualized-auto-sizer": "^1.0.24",
"react-window": "^1.8.10",
"tailwind-merge": "^1.14.0",
"uuid": "^9.0.1",
"viem": "^2.8.13"
Expand Down
166 changes: 113 additions & 53 deletions src/components/file-content-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import {
ConnectDropdownMenuItem,
TreeItem,
} from '@powerhousedao/design-system';
import React, { useRef } from 'react';
import { useTranslation } from 'react-i18next';
import AutoSizer from 'react-virtualized-auto-sizer';
import { VariableSizeGrid as Grid } from 'react-window';
import { FileItem } from 'src/components/file-item';

import { useVirtualizer } from '@tanstack/react-virtual';
import { SetIsWriteMode } from 'src/hooks/useFileOptions';
import { useWindowSize } from 'src/hooks/useWindowSize';

interface IProps {
decodedDriveID: string;
Expand All @@ -28,6 +29,8 @@ const GAP = 8;
const ITEM_WIDTH = 256;
const ITEM_HEIGHT = 48;

const USED_SPACE = 420;

export const FileContentView: React.FC<IProps> = ({
decodedDriveID,
onFileDeleted,
Expand All @@ -38,7 +41,50 @@ export const FileContentView: React.FC<IProps> = ({
onFileOptionsClick,
isAllowedToCreateDocuments,
}) => {
const parentRef = useRef(null);
const { t } = useTranslation();
const windowSize = useWindowSize();

const availableWidth = windowSize.innerWidth - USED_SPACE;

const columnCount = Math.floor(availableWidth / (ITEM_WIDTH + GAP)) || 1;
const rowCount = Math.ceil(files.length / columnCount);

const rowVirtualizer = useVirtualizer({
count: rowCount,
getScrollElement: () => parentRef.current,
estimateSize: index => {
if (index > 0) {
return ITEM_HEIGHT + GAP;
}
return ITEM_HEIGHT;
},
overscan: 5,
});

const columnVirtualizer = useVirtualizer({
horizontal: true,
count: columnCount,
getScrollElement: () => parentRef.current,
estimateSize: index => {
if (index > 0) {
return ITEM_WIDTH + GAP;
}
return ITEM_WIDTH;
},
overscan: 5,
});

const getItemIndex = (rowIndex: number, columnIndex: number) =>
rowIndex * columnCount + columnIndex;

const getItem = (
rowIndex: number,
columnIndex: number,
): TreeItem | null => {
const index = getItemIndex(rowIndex, columnIndex);
return files[index] || null;
};

if (files.length < 1) {
return (
Expand All @@ -48,63 +94,77 @@ export const FileContentView: React.FC<IProps> = ({
);
}

const renderItem = (rowIndex: number, columnIndex: number) => {
const file = getItem(rowIndex, columnIndex);

if (!file) {
return null;
}

return (
<div
style={{
marginLeft: columnIndex === 0 ? 0 : GAP,
}}
>
<FileItem
key={file.id}
file={file}
decodedDriveID={decodedDriveID}
onFileDeleted={onFileDeleted}
onFileSelected={onFileSelected}
itemOptions={fileItemOptions}
onFileOptionsClick={onFileOptionsClick}
isAllowedToCreateDocuments={isAllowedToCreateDocuments}
/>
</div>
);
};

return (
<AutoSizer>
{({ height, width }) => {
const columnCount = Math.floor(width / (ITEM_WIDTH + GAP)) || 1;
const rowCount = Math.ceil(files.length / columnCount);

return (
<Grid
width={width}
height={height}
columnCount={columnCount}
columnWidth={index =>
index === columnCount - 1
? ITEM_WIDTH
: ITEM_WIDTH + GAP
}
rowHeight={index =>
index === rowCount ? ITEM_HEIGHT : ITEM_HEIGHT + GAP
}
rowCount={rowCount}
>
{({ columnIndex, rowIndex, style }) => {
const itemIndex =
rowIndex * columnCount + columnIndex;
const file = files[itemIndex] || null;

if (!file) return null;

return (
<div
ref={parentRef}
style={{
height: `400px`,
width: `100%`,
overflow: 'auto',
}}
>
<div
style={{
height: `${rowVirtualizer.getTotalSize()}px`,
width: `${columnVirtualizer.getTotalSize()}px`,
position: 'relative',
}}
>
{rowVirtualizer.getVirtualItems().map(virtualRow => (
<React.Fragment key={virtualRow.key}>
{columnVirtualizer
.getVirtualItems()
.map(virtualColumn => (
<div
key={virtualColumn.key}
style={{
...style,
marginRight:
columnIndex === columnCount - 1
? 0
: GAP,
position: 'absolute',
top: 0,
left: 0,
marginTop:
virtualRow.index === 0 ? 0 : GAP,
width: `${virtualColumn.size}px`,
height: `${virtualRow.size}px`,
transform: `translateX(${virtualColumn.start}px) translateY(${virtualRow.start}px)`,
}}
>
<FileItem
key={file.id}
file={file}
decodedDriveID={decodedDriveID}
onFileDeleted={onFileDeleted}
onFileSelected={onFileSelected}
itemOptions={fileItemOptions}
onFileOptionsClick={onFileOptionsClick}
isAllowedToCreateDocuments={
isAllowedToCreateDocuments
}
/>
{renderItem(
virtualRow.index,
virtualColumn.index,
)}
</div>
);
}}
</Grid>
);
}}
</AutoSizer>
))}
</React.Fragment>
))}
</div>
</div>
);
};

Expand Down
25 changes: 25 additions & 0 deletions src/hooks/useWindowSize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { useEffect, useState } from 'react';

export const useWindowSize = () => {
const [windowSize, setWindowSize] = useState({
innerWidth: window.innerWidth,
innerHeight: window.innerHeight,
});

useEffect(() => {
const windowSizeHandler = () => {
setWindowSize({
innerWidth: window.innerWidth,
innerHeight: window.innerHeight,
});
};

window.addEventListener('resize', windowSizeHandler);

return () => {
window.removeEventListener('resize', windowSizeHandler);
};
}, []);

return windowSize;
};

0 comments on commit 7e9b024

Please sign in to comment.