-
Notifications
You must be signed in to change notification settings - Fork 27
/
Copy pathTreeTable.tsx
84 lines (70 loc) · 2.59 KB
/
TreeTable.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import React, { Component, Children, createRef } from 'react';
import Column, { ColumnProps } from './Column';
import TreeTableHeader from './TreeTableHeader';
import VirtualList from './VirtualList';
import TreeState from '../model/tree-state';
export type TreeTableProps<TData> = {
// Model properties
value: Readonly<TreeState<TData>>;
onChange?: (value: Readonly<TreeState<TData>>) => void;
// TODO: watch https://github.com/microsoft/TypeScript/issues/21699
// and move to 'required' when possible
// children: Array<React.ReactElement<ColumnProps>>;
children?: Array<React.ReactElement<Column<TData>>> | React.ReactElement<Column<TData>>;
// View callbacks
onScroll?: (scrollTop: number) => void,
// View properties
height?: number; // view height (px)
headerHeight?: number; // header height (px)
className?: string;
}
const TABLE_DEFAULT_HEIGHT = 260;
const noopOnChange = (value: Readonly<TreeState<unknown>>) => {}
const noopOnScroll = (scrollTop: number) => {}
export default class TreeTable<TData> extends Component<TreeTableProps<TData>, {}> {
static Column = Column;
private vListRef = createRef<VirtualList<TData>>();
render() {
const { value, children, onScroll,
height, headerHeight, className } = this.props;
const columnsDef: Array<ColumnProps<TData>> = [];
Children
.toArray(children)
.forEach((node: React.ReactNode) => {
if (isColumnElement<TData>(node)) {
columnsDef.push(node.props);
}
});
return (
<div className={`cp_tree-table ${className != null && className}`}>
<TreeTableHeader columns={columnsDef} height={headerHeight}/>
{ value.hasData && <VirtualList data={value} columns={columnsDef}
height={Number(height) || TABLE_DEFAULT_HEIGHT}
onChange={this.handleChange}
ref={this.vListRef}
onScroll={onScroll || noopOnScroll} /> }
</div>
);
}
private handleChange = (value: Readonly<TreeState<TData>>): void => {
const { onChange } = this.props;
(onChange || noopOnChange)(value);
}
// Public API
scrollTo(posY: number): void {
if (this.vListRef.current != null) {
this.vListRef.current.scrollTo(posY);
}
}
}
function isColumnElement<TData>(elem: any): elem is React.ReactElement<ColumnProps<TData>> {
return checkElementType(elem, Column);
}
function checkElementType<T extends {}>(elem: any, cmpType: React.ComponentType<T>): elem is React.ReactElement<T> {
return (
elem != null &&
elem.type != null &&
elem.type.displayName != null &&
elem.type.displayName === cmpType.displayName
);
}