130 lines
3.2 KiB
TypeScript
130 lines
3.2 KiB
TypeScript
|
import React from 'react';
|
||
|
import {
|
||
|
AutoSizer,
|
||
|
CellMeasurer,
|
||
|
CellMeasurerCache,
|
||
|
List,
|
||
|
} from 'react-virtualized';
|
||
|
|
||
|
import { LocalizerType } from '../../types/Util';
|
||
|
|
||
|
import { PropsActions as MessageActionsType } from './Message';
|
||
|
import { PropsActions as SafetyNumberActionsType } from './SafetyNumberNotification';
|
||
|
|
||
|
type PropsData = {
|
||
|
items: Array<string>;
|
||
|
|
||
|
renderItem: (id: string) => JSX.Element;
|
||
|
};
|
||
|
|
||
|
type PropsHousekeeping = {
|
||
|
i18n: LocalizerType;
|
||
|
};
|
||
|
|
||
|
type PropsActions = MessageActionsType & SafetyNumberActionsType;
|
||
|
|
||
|
type Props = PropsData & PropsHousekeeping & PropsActions;
|
||
|
|
||
|
// from https://github.com/bvaughn/react-virtualized/blob/fb3484ed5dcc41bffae8eab029126c0fb8f7abc0/source/List/types.js#L5
|
||
|
type RowRendererParamsType = {
|
||
|
index: number;
|
||
|
isScrolling: boolean;
|
||
|
isVisible: boolean;
|
||
|
key: string;
|
||
|
parent: Object;
|
||
|
style: Object;
|
||
|
};
|
||
|
|
||
|
export class Timeline extends React.PureComponent<Props> {
|
||
|
public cellSizeCache = new CellMeasurerCache({
|
||
|
defaultHeight: 85,
|
||
|
fixedWidth: true,
|
||
|
});
|
||
|
public mostRecentWidth = 0;
|
||
|
public resizeAllFlag = false;
|
||
|
public listRef = React.createRef<any>();
|
||
|
|
||
|
public componentDidUpdate(prevProps: Props) {
|
||
|
if (this.resizeAllFlag) {
|
||
|
this.resizeAllFlag = false;
|
||
|
this.cellSizeCache.clearAll();
|
||
|
this.recomputeRowHeights();
|
||
|
} else if (this.props.items !== prevProps.items) {
|
||
|
const index = prevProps.items.length;
|
||
|
this.cellSizeCache.clear(index, 0);
|
||
|
this.recomputeRowHeights(index);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public resizeAll = () => {
|
||
|
this.resizeAllFlag = false;
|
||
|
this.cellSizeCache.clearAll();
|
||
|
};
|
||
|
|
||
|
public recomputeRowHeights = (index?: number) => {
|
||
|
if (this.listRef && this.listRef) {
|
||
|
this.listRef.current.recomputeRowHeights(index);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
public rowRenderer = ({
|
||
|
index,
|
||
|
key,
|
||
|
parent,
|
||
|
style,
|
||
|
}: RowRendererParamsType) => {
|
||
|
const { items, renderItem } = this.props;
|
||
|
const messageId = items[index];
|
||
|
|
||
|
return (
|
||
|
<CellMeasurer
|
||
|
cache={this.cellSizeCache}
|
||
|
columnIndex={0}
|
||
|
key={key}
|
||
|
parent={parent}
|
||
|
rowIndex={index}
|
||
|
width={this.mostRecentWidth}
|
||
|
>
|
||
|
<div className="module-timeline__message-container" style={style}>
|
||
|
{renderItem(messageId)}
|
||
|
</div>
|
||
|
</CellMeasurer>
|
||
|
);
|
||
|
};
|
||
|
|
||
|
public render() {
|
||
|
const { items } = this.props;
|
||
|
|
||
|
return (
|
||
|
<div className="module-timeline">
|
||
|
<AutoSizer>
|
||
|
{({ height, width }) => {
|
||
|
if (this.mostRecentWidth && this.mostRecentWidth !== width) {
|
||
|
this.resizeAllFlag = true;
|
||
|
|
||
|
setTimeout(this.resizeAll, 0);
|
||
|
}
|
||
|
|
||
|
this.mostRecentWidth = width;
|
||
|
|
||
|
return (
|
||
|
<List
|
||
|
deferredMeasurementCache={this.cellSizeCache}
|
||
|
height={height}
|
||
|
// This also registers us with parent InfiniteLoader
|
||
|
// onRowsRendered={onRowsRendered}
|
||
|
overscanRowCount={0}
|
||
|
ref={this.listRef}
|
||
|
rowCount={items.length}
|
||
|
rowHeight={this.cellSizeCache.rowHeight}
|
||
|
rowRenderer={this.rowRenderer}
|
||
|
width={width}
|
||
|
/>
|
||
|
);
|
||
|
}}
|
||
|
</AutoSizer>
|
||
|
</div>
|
||
|
);
|
||
|
}
|
||
|
}
|