@controleonline/ui-default 1.0.265 → 1.0.266
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/react/components/table/DefaultDebug.js +234 -233
- package/src/react/components/table/DefaultTable.js +429 -396
- package/src/react/components/table/DefaultTable.styles.js +17 -5
- package/src/react/components/table/DefaultTableControls.js +205 -208
- package/src/react/components/table/DefaultTableRows.js +344 -340
- package/src/react/components/table/useDefaultTableTheme.js +52 -58
- package/src/tests/react/components/table/DefaultTable.test.js +376 -241
|
@@ -1,340 +1,344 @@
|
|
|
1
|
-
import React, { useMemo, useState } from 'react';
|
|
2
|
-
import { FlatList, ScrollView, Text, TouchableOpacity, View } from 'react-native';
|
|
3
|
-
import Icon from 'react-native-vector-icons/Feather';
|
|
4
|
-
import { useStore } from '@store';
|
|
5
|
-
import { formatStoreColumnLabel } from '@controleonline/ui-common/src/react/utils/storeColumns';
|
|
6
|
-
import { getColumnKey } from '../inputs/defaultInputUtils';
|
|
7
|
-
import DefaultColumnFilter from '../filters/DefaultColumnFilter';
|
|
8
|
-
import DefaultTableEmptyState from './DefaultTableEmptyState';
|
|
9
|
-
import DefaultTableInput from './DefaultTableInput';
|
|
10
|
-
import {
|
|
11
|
-
END_REACHED_THRESHOLD,
|
|
12
|
-
getColumnStyle,
|
|
13
|
-
getRowKey,
|
|
14
|
-
getSortField,
|
|
15
|
-
isSortableColumn,
|
|
16
|
-
mergeSortedDataWithLiveItems,
|
|
17
|
-
shouldTriggerEndReachedFromScroll,
|
|
18
|
-
shouldIncludeColumn,
|
|
19
|
-
} from './DefaultTable.utils';
|
|
20
|
-
import styles from './DefaultTable.styles';
|
|
21
|
-
import useDefaultTableTheme from './useDefaultTableTheme';
|
|
22
|
-
|
|
23
|
-
const DefaultTableRows = ({ storeName }) => {
|
|
24
|
-
const store = useStore(storeName);
|
|
25
|
-
const configs = store?.getters?.configs || {};
|
|
26
|
-
const { palette, resolvedAccentColor, themeTokens } = useDefaultTableTheme();
|
|
27
|
-
const columns = Array.isArray(store?.getters?.columns) ? store.getters.columns : [];
|
|
28
|
-
const visibleColumns = store?.getters?.visibleColumns || {};
|
|
29
|
-
const tableColumns = columns.filter(
|
|
30
|
-
column => shouldIncludeColumn(column) && visibleColumns[getColumnKey(column)] !== false,
|
|
31
|
-
);
|
|
32
|
-
const sortedData = mergeSortedDataWithLiveItems({
|
|
33
|
-
liveItems: store?.getters?.items,
|
|
34
|
-
sortedData: configs.sortedData,
|
|
35
|
-
});
|
|
36
|
-
const resolvedFilters = store?.getters?.filters || {};
|
|
37
|
-
const isLoading = Boolean(store?.getters?.isLoadingList || store?.getters?.isLoading);
|
|
38
|
-
const emptyStateLabel = isLoading
|
|
39
|
-
? global.t?.t(storeName, 'label', 'loading')
|
|
40
|
-
: global.t?.t(storeName, 'label', 'empty');
|
|
41
|
-
const tableBorderColor = palette.border;
|
|
42
|
-
const tableEvenColor = themeTokens.listItemEvenRow || themeTokens['bg-even-light'] || palette.background;
|
|
43
|
-
const tableHeaderColor = themeTokens['bg-headers-light'] || resolvedAccentColor;
|
|
44
|
-
const tableMutedColor = palette.textSecondary;
|
|
45
|
-
const tableOddColor = themeTokens.listItemOddRow || themeTokens['bg-odd-light'] || palette.background;
|
|
46
|
-
const tableSurfaceColor = palette.background;
|
|
47
|
-
const tableTextColor = palette.text;
|
|
48
|
-
const rowStyle = configs.rowStyle;
|
|
49
|
-
const hasRowPress = typeof configs.onRowPress === 'function';
|
|
50
|
-
const hasCustomRowActions = typeof configs.rowActionsComponent === 'function';
|
|
51
|
-
const hasEditAction = typeof configs.onEditRow === 'function';
|
|
52
|
-
const hasRowActions = configs.showRowActions !== false && (hasCustomRowActions || hasEditAction);
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
configs.
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
...
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
next.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
const
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
)
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
1
|
+
import React, { useMemo, useState } from 'react';
|
|
2
|
+
import { FlatList, ScrollView, Text, TouchableOpacity, View } from 'react-native';
|
|
3
|
+
import Icon from 'react-native-vector-icons/Feather';
|
|
4
|
+
import { useStore } from '@store';
|
|
5
|
+
import { formatStoreColumnLabel } from '@controleonline/ui-common/src/react/utils/storeColumns';
|
|
6
|
+
import { getColumnKey } from '../inputs/defaultInputUtils';
|
|
7
|
+
import DefaultColumnFilter from '../filters/DefaultColumnFilter';
|
|
8
|
+
import DefaultTableEmptyState from './DefaultTableEmptyState';
|
|
9
|
+
import DefaultTableInput from './DefaultTableInput';
|
|
10
|
+
import {
|
|
11
|
+
END_REACHED_THRESHOLD,
|
|
12
|
+
getColumnStyle,
|
|
13
|
+
getRowKey,
|
|
14
|
+
getSortField,
|
|
15
|
+
isSortableColumn,
|
|
16
|
+
mergeSortedDataWithLiveItems,
|
|
17
|
+
shouldTriggerEndReachedFromScroll,
|
|
18
|
+
shouldIncludeColumn,
|
|
19
|
+
} from './DefaultTable.utils';
|
|
20
|
+
import styles from './DefaultTable.styles';
|
|
21
|
+
import useDefaultTableTheme from './useDefaultTableTheme';
|
|
22
|
+
|
|
23
|
+
const DefaultTableRows = ({ storeName }) => {
|
|
24
|
+
const store = useStore(storeName);
|
|
25
|
+
const configs = store?.getters?.configs || {};
|
|
26
|
+
const { palette, resolvedAccentColor, themeTokens } = useDefaultTableTheme();
|
|
27
|
+
const columns = Array.isArray(store?.getters?.columns) ? store.getters.columns : [];
|
|
28
|
+
const visibleColumns = store?.getters?.visibleColumns || {};
|
|
29
|
+
const tableColumns = columns.filter(
|
|
30
|
+
column => shouldIncludeColumn(column) && visibleColumns[getColumnKey(column)] !== false,
|
|
31
|
+
);
|
|
32
|
+
const sortedData = mergeSortedDataWithLiveItems({
|
|
33
|
+
liveItems: store?.getters?.items,
|
|
34
|
+
sortedData: configs.sortedData,
|
|
35
|
+
});
|
|
36
|
+
const resolvedFilters = store?.getters?.filters || {};
|
|
37
|
+
const isLoading = Boolean(store?.getters?.isLoadingList || store?.getters?.isLoading);
|
|
38
|
+
const emptyStateLabel = isLoading
|
|
39
|
+
? global.t?.t(storeName, 'label', 'loading')
|
|
40
|
+
: global.t?.t(storeName, 'label', 'empty');
|
|
41
|
+
const tableBorderColor = palette.border;
|
|
42
|
+
const tableEvenColor = themeTokens.listItemEvenRow || themeTokens['bg-even-light'] || palette.background;
|
|
43
|
+
const tableHeaderColor = themeTokens['bg-headers-light'] || resolvedAccentColor;
|
|
44
|
+
const tableMutedColor = palette.textSecondary;
|
|
45
|
+
const tableOddColor = themeTokens.listItemOddRow || themeTokens['bg-odd-light'] || palette.background;
|
|
46
|
+
const tableSurfaceColor = palette.background;
|
|
47
|
+
const tableTextColor = palette.text;
|
|
48
|
+
const rowStyle = configs.rowStyle;
|
|
49
|
+
const hasRowPress = typeof configs.onRowPress === 'function';
|
|
50
|
+
const hasCustomRowActions = typeof configs.rowActionsComponent === 'function';
|
|
51
|
+
const hasEditAction = typeof configs.onEditRow === 'function';
|
|
52
|
+
const hasRowActions = configs.showRowActions !== false && (hasCustomRowActions || hasEditAction);
|
|
53
|
+
const shouldPinRowActions = configs.pinRowActions !== false;
|
|
54
|
+
const hasColumnFilters =
|
|
55
|
+
configs.showColumnFiltersButton !== false &&
|
|
56
|
+
configs.tableFiltersVisible === true;
|
|
57
|
+
const actionsCellWidth = hasRowActions ? 96 : 0;
|
|
58
|
+
const [horizontalMetrics, setHorizontalMetrics] = useState({
|
|
59
|
+
contentWidth: 0,
|
|
60
|
+
viewportWidth: 0,
|
|
61
|
+
x: 0,
|
|
62
|
+
});
|
|
63
|
+
const updateHorizontalMetrics = patch => {
|
|
64
|
+
setHorizontalMetrics(current => {
|
|
65
|
+
const next = {
|
|
66
|
+
...current,
|
|
67
|
+
...patch,
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
return next.contentWidth === current.contentWidth &&
|
|
71
|
+
next.viewportWidth === current.viewportWidth &&
|
|
72
|
+
next.x === current.x
|
|
73
|
+
? current
|
|
74
|
+
: next;
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
const stickyBodyTransforms = useMemo(() => {
|
|
78
|
+
const viewportWidth = Number(horizontalMetrics.viewportWidth || 0);
|
|
79
|
+
const contentWidth = Number(horizontalMetrics.contentWidth || 0);
|
|
80
|
+
const x = Number(horizontalMetrics.x || 0);
|
|
81
|
+
const canScrollHorizontally = viewportWidth > 0 && contentWidth > viewportWidth;
|
|
82
|
+
const actionsTranslateX = canScrollHorizontally
|
|
83
|
+
? x + viewportWidth - contentWidth
|
|
84
|
+
: 0;
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
actions:
|
|
88
|
+
shouldPinRowActions && actionsTranslateX !== 0
|
|
89
|
+
? [{ translateX: actionsTranslateX }]
|
|
90
|
+
: null,
|
|
91
|
+
identity: x !== 0 ? [{ translateX: x }] : null,
|
|
92
|
+
};
|
|
93
|
+
}, [horizontalMetrics, shouldPinRowActions]);
|
|
94
|
+
const handleHorizontalScroll = event => {
|
|
95
|
+
updateHorizontalMetrics({
|
|
96
|
+
x: Number(event?.nativeEvent?.contentOffset?.x || 0),
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
const handleHorizontalLayout = event => {
|
|
100
|
+
updateHorizontalMetrics({
|
|
101
|
+
viewportWidth: Number(event?.nativeEvent?.layout?.width || 0),
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
const handleHorizontalContentSizeChange = width => {
|
|
105
|
+
updateHorizontalMetrics({
|
|
106
|
+
contentWidth: Number(width || 0),
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
const handleListScroll = event => {
|
|
110
|
+
if (shouldTriggerEndReachedFromScroll(event)) {
|
|
111
|
+
configs.onEndReached?.();
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const renderTableItem = ({ item: row, index }) => {
|
|
116
|
+
const RowComponent = hasRowPress ? TouchableOpacity : View;
|
|
117
|
+
const rowStyleValue = typeof rowStyle === 'function' ? rowStyle(row, index) : rowStyle;
|
|
118
|
+
const rowPressProps = hasRowPress
|
|
119
|
+
? {
|
|
120
|
+
activeOpacity: 0.84,
|
|
121
|
+
onPress: () => configs.onRowPress(row),
|
|
122
|
+
}
|
|
123
|
+
: {};
|
|
124
|
+
const rowBackgroundColor = index % 2 === 0 ? tableOddColor : tableEvenColor;
|
|
125
|
+
const RowActionsComponent = configs.rowActionsComponent;
|
|
126
|
+
|
|
127
|
+
return (
|
|
128
|
+
<RowComponent
|
|
129
|
+
key={getRowKey(row)}
|
|
130
|
+
style={[
|
|
131
|
+
styles.row,
|
|
132
|
+
{ backgroundColor: rowBackgroundColor, borderBottomColor: tableBorderColor },
|
|
133
|
+
rowStyleValue,
|
|
134
|
+
]}
|
|
135
|
+
{...rowPressProps}
|
|
136
|
+
>
|
|
137
|
+
{tableColumns.map(column => (
|
|
138
|
+
<React.Fragment key={getColumnKey(column)}>
|
|
139
|
+
<DefaultTableInput
|
|
140
|
+
column={column}
|
|
141
|
+
options={column?.isIdentity ? {
|
|
142
|
+
cellStyle: [
|
|
143
|
+
styles.pinnedIdentityCell,
|
|
144
|
+
{
|
|
145
|
+
backgroundColor: rowBackgroundColor,
|
|
146
|
+
...(stickyBodyTransforms.identity
|
|
147
|
+
? { transform: stickyBodyTransforms.identity }
|
|
148
|
+
: {}),
|
|
149
|
+
},
|
|
150
|
+
],
|
|
151
|
+
} : {}}
|
|
152
|
+
row={row}
|
|
153
|
+
storeName={storeName}
|
|
154
|
+
variant="cell"
|
|
155
|
+
/>
|
|
156
|
+
</React.Fragment>
|
|
157
|
+
))}
|
|
158
|
+
{hasRowActions ? (
|
|
159
|
+
<View
|
|
160
|
+
style={[
|
|
161
|
+
styles.cell,
|
|
162
|
+
styles.actionsCell,
|
|
163
|
+
shouldPinRowActions ? styles.pinnedActionsCell : null,
|
|
164
|
+
{
|
|
165
|
+
minWidth: actionsCellWidth,
|
|
166
|
+
width: actionsCellWidth,
|
|
167
|
+
flexBasis: actionsCellWidth,
|
|
168
|
+
maxWidth: actionsCellWidth,
|
|
169
|
+
backgroundColor: rowBackgroundColor,
|
|
170
|
+
...(stickyBodyTransforms.actions
|
|
171
|
+
? { transform: stickyBodyTransforms.actions }
|
|
172
|
+
: {}),
|
|
173
|
+
},
|
|
174
|
+
]}
|
|
175
|
+
>
|
|
176
|
+
<View style={styles.rowActionsGroup}>
|
|
177
|
+
{hasCustomRowActions ? (
|
|
178
|
+
<RowActionsComponent
|
|
179
|
+
openEdit={() => configs.onEditRow?.(row)}
|
|
180
|
+
openRow={hasRowPress ? () => configs.onRowPress(row) : null}
|
|
181
|
+
row={row}
|
|
182
|
+
/>
|
|
183
|
+
) : null}
|
|
184
|
+
{hasEditAction ? (
|
|
185
|
+
<TouchableOpacity
|
|
186
|
+
style={[styles.iconButton, { borderColor: tableBorderColor, backgroundColor: tableSurfaceColor }]}
|
|
187
|
+
activeOpacity={0.82}
|
|
188
|
+
onPress={() => configs.onEditRow?.(row)}
|
|
189
|
+
>
|
|
190
|
+
<Icon name="edit-2" size={14} color={tableMutedColor} />
|
|
191
|
+
</TouchableOpacity>
|
|
192
|
+
) : null}
|
|
193
|
+
</View>
|
|
194
|
+
</View>
|
|
195
|
+
) : null}
|
|
196
|
+
</RowComponent>
|
|
197
|
+
);
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
return (
|
|
201
|
+
<>
|
|
202
|
+
<ScrollView
|
|
203
|
+
horizontal
|
|
204
|
+
onContentSizeChange={handleHorizontalContentSizeChange}
|
|
205
|
+
onLayout={handleHorizontalLayout}
|
|
206
|
+
onScroll={handleHorizontalScroll}
|
|
207
|
+
scrollEventThrottle={16}
|
|
208
|
+
style={styles.scroll}
|
|
209
|
+
contentContainerStyle={styles.horizontalScrollContent}
|
|
210
|
+
>
|
|
211
|
+
<View style={styles.content}>
|
|
212
|
+
<View style={[styles.headerRow, { backgroundColor: tableHeaderColor, borderBottomColor: tableBorderColor }]}>
|
|
213
|
+
{tableColumns.map(column => {
|
|
214
|
+
const fieldName = getColumnKey(column);
|
|
215
|
+
const label = formatStoreColumnLabel({
|
|
216
|
+
columns,
|
|
217
|
+
fieldName,
|
|
218
|
+
fallbackLabel: column?.label || fieldName,
|
|
219
|
+
storeName,
|
|
220
|
+
});
|
|
221
|
+
const sortFieldName = getSortField(column);
|
|
222
|
+
|
|
223
|
+
return (
|
|
224
|
+
<TouchableOpacity
|
|
225
|
+
key={fieldName}
|
|
226
|
+
style={[
|
|
227
|
+
getColumnStyle(column),
|
|
228
|
+
column?.isIdentity
|
|
229
|
+
? [styles.stickyIdentityCell, styles.stickyHeaderCell, { backgroundColor: tableHeaderColor }]
|
|
230
|
+
: null,
|
|
231
|
+
]}
|
|
232
|
+
activeOpacity={isSortableColumn(column) ? 0.8 : 1}
|
|
233
|
+
onPress={() => configs.requestSort?.(column)}
|
|
234
|
+
>
|
|
235
|
+
<View style={styles.sortableHeader}>
|
|
236
|
+
<Text style={[styles.headerText, { color: tableTextColor }]} numberOfLines={1}>{label}</Text>
|
|
237
|
+
{isSortableColumn(column) && configs.resolvedSort?.field === sortFieldName ? (
|
|
238
|
+
<Icon name={configs.resolvedSort?.direction === 'desc' ? 'chevron-down' : 'chevron-up'} size={12} color={tableTextColor} />
|
|
239
|
+
) : isSortableColumn(column) ? (
|
|
240
|
+
<Icon name="chevrons-up" size={12} color={tableBorderColor} />
|
|
241
|
+
) : null}
|
|
242
|
+
{resolvedFilters?.[fieldName] ? <Icon name="filter" size={11} color={tableTextColor} /> : null}
|
|
243
|
+
</View>
|
|
244
|
+
</TouchableOpacity>
|
|
245
|
+
);
|
|
246
|
+
})}
|
|
247
|
+
{hasRowActions ? (
|
|
248
|
+
<View
|
|
249
|
+
style={[
|
|
250
|
+
styles.cell,
|
|
251
|
+
styles.actionsCell,
|
|
252
|
+
shouldPinRowActions ? styles.stickyActionsCell : null,
|
|
253
|
+
shouldPinRowActions ? styles.stickyHeaderCell : null,
|
|
254
|
+
{
|
|
255
|
+
minWidth: actionsCellWidth,
|
|
256
|
+
width: actionsCellWidth,
|
|
257
|
+
flexBasis: actionsCellWidth,
|
|
258
|
+
maxWidth: actionsCellWidth,
|
|
259
|
+
backgroundColor: tableHeaderColor,
|
|
260
|
+
},
|
|
261
|
+
]}
|
|
262
|
+
>
|
|
263
|
+
<Text style={[styles.headerText, { color: tableTextColor }]}>
|
|
264
|
+
{global.t?.t(storeName, 'label', 'actions')}
|
|
265
|
+
</Text>
|
|
266
|
+
</View>
|
|
267
|
+
) : null}
|
|
268
|
+
</View>
|
|
269
|
+
{hasColumnFilters ? (
|
|
270
|
+
<View style={[styles.filterRow, { backgroundColor: tableHeaderColor, borderBottomColor: tableBorderColor }]}>
|
|
271
|
+
{tableColumns.map(column => {
|
|
272
|
+
const fieldName = getColumnKey(column);
|
|
273
|
+
|
|
274
|
+
return (
|
|
275
|
+
<View
|
|
276
|
+
key={`${fieldName}-filter`}
|
|
277
|
+
style={[
|
|
278
|
+
getColumnStyle(column),
|
|
279
|
+
column?.isIdentity
|
|
280
|
+
? [styles.stickyIdentityCell, { backgroundColor: tableHeaderColor }]
|
|
281
|
+
: null,
|
|
282
|
+
]}
|
|
283
|
+
>
|
|
284
|
+
{column?.filter !== false && column?.filters !== false ? (
|
|
285
|
+
<DefaultColumnFilter
|
|
286
|
+
column={column}
|
|
287
|
+
filters={resolvedFilters}
|
|
288
|
+
storeName={storeName}
|
|
289
|
+
style={styles.filterCell}
|
|
290
|
+
/>
|
|
291
|
+
) : null}
|
|
292
|
+
</View>
|
|
293
|
+
);
|
|
294
|
+
})}
|
|
295
|
+
{hasRowActions ? (
|
|
296
|
+
<View
|
|
297
|
+
style={[
|
|
298
|
+
styles.cell,
|
|
299
|
+
styles.actionsCell,
|
|
300
|
+
shouldPinRowActions ? styles.stickyActionsCell : null,
|
|
301
|
+
{
|
|
302
|
+
minWidth: actionsCellWidth,
|
|
303
|
+
width: actionsCellWidth,
|
|
304
|
+
flexBasis: actionsCellWidth,
|
|
305
|
+
maxWidth: actionsCellWidth,
|
|
306
|
+
backgroundColor: tableHeaderColor,
|
|
307
|
+
},
|
|
308
|
+
]}
|
|
309
|
+
/>
|
|
310
|
+
) : null}
|
|
311
|
+
</View>
|
|
312
|
+
) : null}
|
|
313
|
+
|
|
314
|
+
<FlatList
|
|
315
|
+
data={sortedData}
|
|
316
|
+
keyExtractor={getRowKey}
|
|
317
|
+
renderItem={renderTableItem}
|
|
318
|
+
style={styles.tableList}
|
|
319
|
+
contentContainerStyle={styles.tableListContent}
|
|
320
|
+
ListEmptyComponent={(
|
|
321
|
+
<DefaultTableEmptyState
|
|
322
|
+
emptyStateLabel={emptyStateLabel}
|
|
323
|
+
isLoading={isLoading}
|
|
324
|
+
isTable
|
|
325
|
+
tableMutedColor={tableMutedColor}
|
|
326
|
+
/>
|
|
327
|
+
)}
|
|
328
|
+
ListFooterComponent={null}
|
|
329
|
+
nestedScrollEnabled
|
|
330
|
+
onMomentumScrollBegin={configs.onMomentumScrollBegin || undefined}
|
|
331
|
+
onScroll={handleListScroll}
|
|
332
|
+
onScrollBeginDrag={configs.onScrollBeginDrag || undefined}
|
|
333
|
+
onEndReached={configs.onEndReached}
|
|
334
|
+
onEndReachedThreshold={END_REACHED_THRESHOLD}
|
|
335
|
+
scrollEventThrottle={120}
|
|
336
|
+
showsVerticalScrollIndicator={false}
|
|
337
|
+
/>
|
|
338
|
+
</View>
|
|
339
|
+
</ScrollView>
|
|
340
|
+
</>
|
|
341
|
+
);
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
export default DefaultTableRows;
|