Skip to content

Commit 0bb0470

Browse files
committed
feat: update table
1 parent c99a75d commit 0bb0470

File tree

4 files changed

+257
-7
lines changed

4 files changed

+257
-7
lines changed

src/components/Table/Table.tsx

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ const Table = forwardRef(
4545
{
4646
flexDirection: layout == 'horizontal' ? 'row' : 'column',
4747
display: 'flex',
48-
flex: 1,
48+
width: '100%',
4949
},
5050
style,
5151
]}
@@ -65,7 +65,12 @@ const Table = forwardRef(
6565
{columns.map((column, cidx) => (
6666
<View
6767
key={cidx}
68-
style={[{ flex: 1 }, column.style, column.headerStyle]}
68+
style={[
69+
{ flex: layout == 'horizontal' ? 0 : 1 },
70+
71+
column.style,
72+
column.headerStyle,
73+
]}
6974
>
7075
{column.renderTitle ? (
7176
<Fragment>{column.renderTitle(column.title)}</Fragment>
@@ -96,7 +101,13 @@ const Table = forwardRef(
96101
]}
97102
>
98103
{columns.map((column, cidx) => (
99-
<View key={cidx} style={[{ flex: 1 }, column.style]}>
104+
<View
105+
key={cidx}
106+
style={[
107+
{ flex: layout == 'horizontal' ? 0 : 1 },
108+
column.style,
109+
]}
110+
>
100111
{column.render ? (
101112
column.render(
102113
column.dataIndex ? item[column.dataIndex] : item

src/components/Table/Table.types.ts

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import type { StyleProp, TextStyle, ViewStyle } from 'react-native';
1+
import type { ReactElement } from 'react';
2+
import type {
3+
FlatListProps,
4+
RefreshControlProps,
5+
StyleProp,
6+
TextStyle,
7+
ViewStyle,
8+
} from 'react-native';
29

310
export type Column<T = any> = {
411
title: string;
@@ -12,14 +19,41 @@ export type Column<T = any> = {
1219
};
1320

1421
export type TableProps<T = any> = {
15-
dataSource?: T[];
22+
dataSource: T[];
1623
columns: Column<T>[];
1724
groupBy?: keyof T;
1825
layout?: 'vertical' | 'horizontal';
19-
renderHeader?: (columns: Column<T>[]) => React.ReactNode;
26+
renderHeader?: (columns: Column<T>[]) => React.ReactElement;
27+
2028
headerStyle?: StyleProp<ViewStyle> | undefined;
2129
rowStyle?: StyleProp<ViewStyle> | undefined;
30+
rowKey?: keyof T | ((item: T) => string);
2231
onRow?: (record: T, index: number) => void;
2332
style?: StyleProp<ViewStyle> | undefined;
33+
renderRow?: (props: RenderRowProps<T>) => ReactElement;
34+
scrollEnabled?: boolean;
35+
36+
isStickyHeader?: boolean;
37+
38+
refreshControl?: React.ReactElement<RefreshControlProps>;
39+
40+
isRefreshing?: boolean;
41+
42+
onRefresh?: () => void;
43+
44+
isNoData?: boolean;
45+
46+
noDataContent?: React.ReactElement | string;
47+
48+
};
49+
50+
export type TableFlatListProps<T = any> = TableProps<T> &
51+
Omit<FlatListProps<T>, 'data' | 'renderItem'>;
52+
53+
export type RenderRowProps<T = any> = {
54+
record: T;
55+
index: number;
56+
children: ReactElement;
2457
};
58+
2559
export type TableRef = {};
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
import React, { forwardRef, Fragment, memo, useCallback } from 'react';
2+
import { FlatList, RefreshControl, Text, View } from 'react-native';
3+
4+
import type { Column, TableFlatListProps, TableRef } from './Table.types';
5+
import type { ViewProps } from 'react-native';
6+
7+
export type NoDataProps = ViewProps & {
8+
message?: string | null | undefined;
9+
};
10+
11+
const NoData = ({ message }: NoDataProps) => {
12+
return (
13+
<View>
14+
<Text>{message}</Text>
15+
</View>
16+
);
17+
};
18+
19+
export const isNullOrUndefined = (data?: any): data is null | undefined =>
20+
data === null || data === undefined;
21+
22+
const RowItem = memo(
23+
forwardRef(({ item, index, columns, rowStyle, layout }: any, ref) => {
24+
return (
25+
<View
26+
style={[
27+
{
28+
flex: layout === 'vertical' ? 1 : undefined,
29+
flexDirection: layout === 'horizontal' ? 'column' : 'row',
30+
},
31+
rowStyle
32+
? typeof rowStyle === 'function'
33+
? rowStyle(item, index)
34+
: rowStyle
35+
: {},
36+
]}
37+
>
38+
{columns.map((column: Column, cidx: React.Key | null | undefined) => (
39+
<View
40+
key={cidx}
41+
style={[{ flex: layout == 'horizontal' ? 0 : 1 }, column.style]}
42+
>
43+
{column.render ? (
44+
column.render(
45+
column.dataIndex ? item[column.dataIndex] : item,
46+
index
47+
)
48+
) : (
49+
<Text>{item[column.key]}</Text>
50+
)}
51+
</View>
52+
))}
53+
</View>
54+
);
55+
})
56+
);
57+
58+
const TableFlatlist = forwardRef(
59+
(
60+
{
61+
dataSource,
62+
columns,
63+
groupBy,
64+
layout,
65+
renderHeader,
66+
headerStyle,
67+
rowStyle,
68+
rowKey,
69+
style,
70+
renderRow,
71+
scrollEnabled = false,
72+
isStickyHeader,
73+
isNoData,
74+
noDataContent,
75+
...flatListProps
76+
}: TableFlatListProps,
77+
ref?: React.Ref<TableRef | undefined> | undefined
78+
) => {
79+
const isNoDataSource =
80+
(isNullOrUndefined(isNoData) && dataSource.length === 0) ||
81+
(!isNullOrUndefined(isNoData) && isNoData);
82+
83+
dataSource = isNoDataSource ? noDataSource : dataSource;
84+
const flatListPropsInner = { ...flatListProps };
85+
86+
if (!flatListPropsInner.refreshControl) {
87+
if (flatListPropsInner.onRefresh) {
88+
const onRefresh = flatListPropsInner.onRefresh;
89+
const isRefreshing = flatListPropsInner.isRefreshing;
90+
flatListPropsInner.refreshControl = (
91+
<RefreshControl refreshing={!!isRefreshing} onRefresh={onRefresh} />
92+
);
93+
}
94+
delete flatListPropsInner.onRefresh;
95+
delete flatListPropsInner.isRefreshing;
96+
}
97+
98+
const renderNoDataItem = useCallback(() => {
99+
if (
100+
typeof noDataContent === 'string' ||
101+
isNullOrUndefined(noDataContent)
102+
) {
103+
return <NoData message={noDataContent} />;
104+
}
105+
106+
return noDataContent!;
107+
}, [noDataContent]);
108+
109+
const renderItem = useCallback(({ item, index }: any) => {
110+
if (renderRow) {
111+
return renderRow({
112+
record: item,
113+
index,
114+
children: (
115+
<RowItem
116+
index={index}
117+
item={item}
118+
columns={columns}
119+
rowStyle={rowStyle}
120+
layout={layout}
121+
/>
122+
),
123+
});
124+
}
125+
126+
return (
127+
<RowItem
128+
index={index}
129+
item={item}
130+
columns={columns}
131+
rowStyle={rowStyle}
132+
layout={layout}
133+
/>
134+
);
135+
}, []);
136+
137+
const keyExtractor = useCallback((item: any, index: any) => {
138+
return rowKey
139+
? typeof rowKey === 'function'
140+
? rowKey(item)
141+
: item[rowKey]
142+
: `row-${index}`;
143+
// eslint-disable-next-line react-hooks/exhaustive-deps
144+
}, []);
145+
146+
const listHeaderComponent = useCallback((): React.ReactElement => {
147+
if (renderHeader) {
148+
return renderHeader(columns);
149+
}
150+
return (
151+
<View
152+
style={[
153+
{
154+
flexDirection: layout === 'horizontal' ? 'column' : 'row',
155+
flex: layout === 'vertical' ? 1 : undefined,
156+
},
157+
headerStyle,
158+
]}
159+
>
160+
{columns.map((column, cidx) => (
161+
<View
162+
key={cidx}
163+
style={[
164+
{ flex: layout == 'horizontal' ? 0 : 1 },
165+
column.style,
166+
column.headerStyle,
167+
]}
168+
>
169+
{column.renderTitle ? (
170+
<Fragment>{column.renderTitle(column.title)}</Fragment>
171+
) : (
172+
<>
173+
<Text style={[column.titleStyle]}>{column.title}</Text>
174+
</>
175+
)}
176+
</View>
177+
))}
178+
</View>
179+
);
180+
// eslint-disable-next-line react-hooks/exhaustive-deps
181+
}, []);
182+
183+
return (
184+
<FlatList
185+
style={[{ display: 'flex' }, style]}
186+
scrollEnabled={scrollEnabled}
187+
data={dataSource}
188+
windowSize={30}
189+
initialNumToRender={20}
190+
renderItem={isNoDataSource ? renderNoDataItem : renderItem}
191+
maxToRenderPerBatch={6}
192+
keyExtractor={keyExtractor}
193+
ListHeaderComponent={listHeaderComponent}
194+
stickyHeaderIndices={isStickyHeader ? [0] : undefined}
195+
horizontal={layout === 'horizontal'}
196+
{...flatListPropsInner}
197+
/>
198+
);
199+
}
200+
);
201+
202+
export default TableFlatlist;
203+
204+
const noDataSource = [{ id: 'no_data', type: 'no_data' }];

src/components/Table/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
import Table from './Table';
2+
import TableFlatlist from './TableFlatlist';
23
export * from './Table.types';
3-
export { Table };
4+
export { Table, TableFlatlist };

0 commit comments

Comments
 (0)