123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- import {Fragment} from 'react';
- import {AutoSizer, List as ReactVirtualizedList} from 'react-virtualized';
- import Row from './row';
- import {ItemsAfterFilter} from './types';
- type RowProps = Pick<
- React.ComponentProps<typeof Row>,
- 'itemSize' | 'inputValue' | 'getItemProps' | 'registerVisibleItem'
- >;
- type Props = {
- /**
- * The item index that is currently isActive
- */
- highlightedIndex: number;
- /**
- * Flat item array or grouped item array
- */
- items: ItemsAfterFilter;
- /**
- * Max height of dropdown menu. Units are assumed as `px`
- */
- maxHeight: number;
- /**
- * Callback for when dropdown menu is being scrolled
- */
- onScroll?: () => void;
- /**
- * Supplying this height will force the dropdown menu to be a virtualized
- * list. This is very useful (and probably required) if you have a large list.
- * e.g. Project selector with many projects.
- *
- * Currently, our implementation of the virtualized list requires a fixed
- * height.
- */
- virtualizedHeight?: number;
- /**
- * If you use grouping with virtualizedHeight, the labels will be that height
- * unless specified here
- */
- virtualizedLabelHeight?: number;
- } & RowProps;
- function getHeight(
- items: ItemsAfterFilter,
- maxHeight: number,
- virtualizedHeight: number,
- virtualizedLabelHeight?: number
- ) {
- const minHeight = virtualizedLabelHeight
- ? items.reduce(
- (a, r) => a + (r.groupLabel ? virtualizedLabelHeight : virtualizedHeight),
- 0
- )
- : items.length * virtualizedHeight;
- return Math.min(minHeight, maxHeight);
- }
- const List = ({
- virtualizedHeight,
- virtualizedLabelHeight,
- onScroll,
- items,
- highlightedIndex,
- maxHeight,
- ...rowProps
- }: Props) => {
- if (virtualizedHeight) {
- return (
- <AutoSizer disableHeight>
- {({width}) => (
- <ReactVirtualizedList
- style={{outline: 'none'}}
- width={width}
- height={getHeight(
- items,
- maxHeight,
- virtualizedHeight,
- virtualizedLabelHeight
- )}
- onScroll={onScroll}
- rowCount={items.length}
- rowHeight={({index}) =>
- items[index].groupLabel && virtualizedLabelHeight
- ? virtualizedLabelHeight
- : virtualizedHeight
- }
- rowRenderer={({key, index, style}) => (
- <Row
- key={key}
- style={style}
- item={items[index]}
- isHighlighted={items[index].index === highlightedIndex}
- {...rowProps}
- />
- )}
- />
- )}
- </AutoSizer>
- );
- }
- return (
- <Fragment>
- {items.map((item, index) => (
- <Row
- // Using only the index of the row might not re-render properly,
- // because the items shift around the list
- key={`${item.value}-${index}`}
- item={item}
- isHighlighted={item.index === highlightedIndex}
- {...rowProps}
- />
- ))}
- </Fragment>
- );
- };
- export default List;
|