Skip to content

Commit

Permalink
feat(FileOrganizer): added gridRef prop to allow access to react-wind…
Browse files Browse the repository at this point in the history
…ow grid
  • Loading branch information
liamross committed May 27, 2020
1 parent d6c7c91 commit 77c0c0e
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 41 deletions.
2 changes: 1 addition & 1 deletion src/components/ClickableDiv/ClickableDiv.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export interface ClickableDivProps extends Remove<HTMLAttributes<HTMLDivElement>
export const ClickableDiv = forwardRef<HTMLDivElement, ClickableDivProps>(
({ onClick, onKeyPress, disabled, noFocusStyle, usePointer, className, children, tabIndex, ...divProps }, ref) => {
const clickableDivRef = useRef<HTMLDivElement>(null);
useImperativeHandle(ref, () => clickableDivRef.current!);
useImperativeHandle(ref, () => clickableDivRef.current as HTMLDivElement);

const handleOnClick = useOnClick(onClick, { disabled, stopPropagation: true });

Expand Down
2 changes: 1 addition & 1 deletion src/components/Draggable/Draggable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export const Draggable = forwardRef<HTMLDivElement, DraggableProps>(
ref,
) => {
const draggableRef = useRef<HTMLDivElement>(null);
useImperativeHandle(ref, () => draggableRef.current!);
useImperativeHandle(ref, () => draggableRef.current as HTMLDivElement);

/* --- Drag and drop settings. --- */

Expand Down
2 changes: 1 addition & 1 deletion src/components/EditableText/EditableText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export const EditableText = forwardRef<HTMLDivElement, EditableTextProps>(
const inputRef = useRef<HTMLInputElement>(null);

const buttonRef = useRef<HTMLDivElement>(null);
useImperativeHandle(ref, () => buttonRef.current!);
useImperativeHandle(ref, () => buttonRef.current as HTMLDivElement);

// Use state if controlled edit mode not provided.
const [stateEditMode, setStateEditMode] = useState(false);
Expand Down
77 changes: 46 additions & 31 deletions src/components/FileOrganizer/FileOrganizer.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { boolean, number } from '@storybook/addon-knobs';
import React, { FC, useCallback, useEffect, useState } from 'react';
import React, { FC, useCallback, useEffect, useState, useRef } from 'react';
import { useManagedFiles } from '../../hooks';
import { action } from '../../storybook-helpers/action/action';
import { createFile, FakeFile } from '../../storybook-helpers/data/files';
Expand All @@ -10,6 +10,8 @@ import { Icon } from '../Icon';
import { Thumbnail } from '../Thumbnail';
import { ThumbnailDragLayer } from '../ThumbnailDragLayer';
import readme from './README.md';
import { FixedSizeGrid } from 'react-window';
import { Button } from '../Button';

export default {
title: 'Components/FileOrganizer',
Expand All @@ -21,9 +23,10 @@ interface TemplateProps {
onRenderDragLayer?: boolean;
numFiles?: number;
editable?: boolean;
scrollToTop?: boolean;
}

const Template: FC<TemplateProps> = ({ onRenderDragLayer, numFiles = 2, editable }) => {
const Template: FC<TemplateProps> = ({ onRenderDragLayer, numFiles = 2, editable, scrollToTop }) => {
// This is the index organizing function.
const [files, setFiles] = useState<FakeFile[]>([]);
const handleOnMove = useCallback<NonNullable<FileOrganizerProps<FakeFile>['onMove']>>((fromIndex, toIndex) => {
Expand All @@ -37,6 +40,11 @@ const Template: FC<TemplateProps> = ({ onRenderDragLayer, numFiles = 2, editable
return true;
}, []);

const gridRef = useRef<FixedSizeGrid>(null);
const onScrollToTop = () => {
gridRef.current?.scrollTo({ scrollTop: 0, scrollLeft: 0 });
};

// This is just a helper for adding or removing files.
useEffect(() => {
setFiles((prev) => {
Expand All @@ -55,35 +63,39 @@ const Template: FC<TemplateProps> = ({ onRenderDragLayer, numFiles = 2, editable
}, [numFiles]);

return (
<FileOrganizer
files={files}
preventArrowsToMove={boolean('preventArrowsToMove', false)}
preventClickAwayDeselect={boolean('preventClickAwayDeselect', false)}
disableMove={boolean('disableMove', false)}
padding={integer('padding', 0)}
onMove={forwardAction('onMove', handleOnMove)}
onDragChange={action('onDragChange')}
onDeselectAll={action('onDeselectAll')}
onSelectAll={action('onSelectAll')}
onRenderDragLayer={onRenderDragLayer ? () => <ThumbnailDragLayer /> : undefined}
onRenderThumbnail={({ onRenderThumbnailProps }) => (
<Thumbnail
{...onRenderThumbnailProps}
onRename={editable ? () => {} : undefined}
buttonProps={
editable
? [
{
children: <Icon icon="Close" />,
onClick: () => {},
key: 0,
},
]
: undefined
}
/>
)}
/>
<>
<FileOrganizer
files={files}
gridRef={gridRef}
preventArrowsToMove={boolean('preventArrowsToMove', false)}
preventClickAwayDeselect={boolean('preventClickAwayDeselect', false)}
disableMove={boolean('disableMove', false)}
padding={integer('padding', 0)}
onMove={forwardAction('onMove', handleOnMove)}
onDragChange={action('onDragChange')}
onDeselectAll={action('onDeselectAll')}
onSelectAll={action('onSelectAll')}
onRenderDragLayer={onRenderDragLayer ? () => <ThumbnailDragLayer /> : undefined}
onRenderThumbnail={({ onRenderThumbnailProps }) => (
<Thumbnail
{...onRenderThumbnailProps}
onRename={editable ? () => {} : undefined}
buttonProps={
editable
? [
{
children: <Icon icon="Close" />,
onClick: () => {},
key: 0,
},
]
: undefined
}
/>
)}
/>
{scrollToTop && <Button onClick={onScrollToTop}>Scroll to top</Button>}
</>
);
};

Expand All @@ -99,6 +111,9 @@ export const WithCustomDragLayer = () => {
const numFiles = number('number of files', 2, { min: 0, max: 16, step: 1, range: true });
return <Template numFiles={numFiles} onRenderDragLayer />;
};
export const WithGridRef = () => {
return <Template numFiles={100} scrollToTop />;
};

export const UseManagedFilesHook = () => {
const { fileOrganizerProps, getThumbnailSelectionProps, draggingIds } = useManagedFiles({
Expand Down
12 changes: 10 additions & 2 deletions src/components/FileOrganizer/FileOrganizer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ import React, {
useEffect,
useRef,
useState,
Ref,
useImperativeHandle,
} from 'react';
import { FixedSizeGrid as Grid } from 'react-window';
import { FixedSizeGrid } from 'react-window';
import {
getRowAndColumnIndex,
getSibling,
Expand Down Expand Up @@ -64,6 +66,10 @@ export interface FileOrganizerProps<F> extends HTMLAttributes<HTMLDivElement> {
* ensure that the elements are positioned properly.
*/
padding?: number;
/**
* If provided, the ref is attached to the `react-window` FixedSizeGrid.
*/
gridRef?: Ref<FixedSizeGrid>;
/**
* On render function for generating the thumbnails for the page organizer.
* If you do not want to build your own, try using the `Thumbnail` component.
Expand Down Expand Up @@ -133,14 +139,16 @@ export function FileOrganizer<F extends ObjectWithId>({
preventClickAwayDeselect,
draggingIds,
padding,
gridRef: _gridRef,
className,
onClick,
onKeyDown,
style,
...divProps
}: FileOrganizerProps<F>) {
const fileOrganizerRef = useRef<HTMLDivElement>(null);
const gridRef = useRef<Grid>(null);
const gridRef = useRef<FixedSizeGrid>(null);
useImperativeHandle(_gridRef, () => gridRef.current as FixedSizeGrid);

const [columnCount, setColumnCount] = useState(0);

Expand Down
10 changes: 5 additions & 5 deletions src/components/FileOrganizer/MemoAutoSizer.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { forwardRef, memo, useCallback, useEffect, useMemo } from 'react';
import AutoSizer, { Size } from 'react-virtualized-auto-sizer';
import { FixedSizeGrid as Grid, GridChildComponentProps } from 'react-window';
import { FixedSizeGrid, GridChildComponentProps } from 'react-window';
import { getItemIndex, ObjectWithId } from '../../utils';

interface VirtualizedProps {
Expand All @@ -19,7 +19,7 @@ const MemoGridItem = memo<GridChildComponentProps>(({ columnIndex, rowIndex, sty
});

const MemoGrid = memo(
forwardRef<Grid, Size & VirtualizedProps>(
forwardRef<FixedSizeGrid, Size & VirtualizedProps>(
({ width, height, files, padding, renderItem, onColumnCountChange, size }, ref) => {
const modifiedHeight = height - 2 * padding;
const modifiedWidth = width - 2 * padding;
Expand All @@ -35,7 +35,7 @@ const MemoGrid = memo(
}, [onColumnCountChange, data.columnCount]);

return (
<Grid
<FixedSizeGrid
ref={ref}
columnWidth={size.width}
rowHeight={size.height}
Expand All @@ -51,14 +51,14 @@ const MemoGrid = memo(
}}
>
{MemoGridItem}
</Grid>
</FixedSizeGrid>
);
},
),
);

export const MemoAutoSizer = memo(
forwardRef<Grid, VirtualizedProps>(({ files, padding, size, renderItem, onColumnCountChange }, ref) => {
forwardRef<FixedSizeGrid, VirtualizedProps>(({ files, padding, size, renderItem, onColumnCountChange }, ref) => {
const onRenderGrid = useCallback(
({ width, height }: Size) => (
<MemoGrid
Expand Down

0 comments on commit 77c0c0e

Please sign in to comment.