@controleonline/ui-default 1.0.277 → 1.0.279
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/docs/compact-order-history-1047.md +25 -0
- package/package.json +1 -1
- package/src/react/components/filters/CompactFilterSelector.js +194 -185
- package/src/react/components/filters/DefaultColumnFilter.js +8 -6
- package/src/react/components/filters/DefaultCompactFilterPicker.js +35 -0
- package/src/react/components/table/DefaultColumnMenu.js +36 -2
- package/src/react/components/table/DefaultCompactDialog.js +36 -0
- package/src/react/components/table/DefaultDebug.js +199 -197
- package/src/react/components/table/DefaultFiltersModal.js +44 -12
- package/src/react/components/table/DefaultTable.js +27 -27
- package/src/react/components/table/DefaultTableCards.js +44 -10
- package/src/react/components/table/DefaultTableCompact.helpers.js +26 -0
- package/src/react/components/table/DefaultTableCompact.styles.js +28 -0
- package/src/react/components/table/DefaultTableCompactToolbar.js +112 -0
- package/src/react/components/table/DefaultTableInput.js +30 -11
- package/src/react/components/table/DefaultTablePaginationBar.js +38 -0
- package/src/react/components/table/DefaultTableRows.js +17 -9
- package/src/react/components/table/DefaultTableToolbar.js +7 -0
- package/src/react/components/table/DefaultTableView.js +5 -2
- package/src/react/components/table/useDefaultTableCreateForm.js +29 -0
- package/src/react/components/table/useDefaultTablePagination.js +15 -1
- package/src/react/components/table/useDefaultTableRowInteraction.js +19 -0
- package/src/react/components/table/useDefaultTableStoreSync.js +30 -21
- package/src/react/components/table/useDefaultTableTheme.js +44 -41
- package/src/tests/react/components/table/DefaultTable.group1.test.js +441 -0
- package/src/tests/react/components/table/DefaultTable.group2.test.js +453 -0
- package/src/tests/react/components/table/DefaultTable.group3.test.js +289 -0
- package/src/tests/react/components/table/DefaultTable.test.js +1 -1381
- package/src/tests/react/components/table/DefaultTableToolbar.waiter.test.js +1 -0
- package/src/tests/react/components/table/compactDialogs.test.js +53 -0
- package/src/tests/react/components/table/compactFilters.test.js +47 -0
- package/src/tests/react/components/table/compactPagination.test.js +66 -0
- package/src/tests/react/components/table/compactTheme.test.js +34 -0
- package/src/tests/react/components/table/compactToolbar.test.js +41 -0
- package/src/tests/react/components/table/defaultTableStoreHarness.cjs +35 -0
- package/src/tests/react/components/table/defaultTableTestSetup.cjs +207 -0
- package/src/tests/react/components/table/useDefaultTableStoreSync.test.js +38 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, {useEffect, useState} from 'react';
|
|
2
2
|
import { Modal, ScrollView, Text, TouchableOpacity, View } from 'react-native';
|
|
3
3
|
import Icon from 'react-native-vector-icons/Feather';
|
|
4
4
|
import { useStore } from '@store';
|
|
@@ -6,6 +6,7 @@ import { formatStoreColumnLabel } from '@controleonline/ui-common/src/react/util
|
|
|
6
6
|
import DefaultColumnFilter from '../filters/DefaultColumnFilter';
|
|
7
7
|
import { getColumnKey, normalizeText } from '../inputs/defaultInputUtils';
|
|
8
8
|
import styles from './DefaultTable.styles';
|
|
9
|
+
import {getCompactColumnLabel} from './DefaultTableCompact.helpers';
|
|
9
10
|
import { shouldIncludeColumn } from './DefaultTable.utils';
|
|
10
11
|
import {
|
|
11
12
|
persistTableFiltersPreference,
|
|
@@ -13,8 +14,9 @@ import {
|
|
|
13
14
|
sanitizeTableFiltersPreference,
|
|
14
15
|
} from '../../utils/tableVisibleColumnsPreferences';
|
|
15
16
|
import useDefaultTableTheme from './useDefaultTableTheme';
|
|
17
|
+
import DefaultCompactDialog from './DefaultCompactDialog';
|
|
16
18
|
|
|
17
|
-
const DefaultFiltersModal = ({ storeName, visible = false, onClose }) => {
|
|
19
|
+
const DefaultFiltersModal = ({ storeName, visible = false, deferred = false, onClose }) => {
|
|
18
20
|
const store = useStore(storeName);
|
|
19
21
|
const columns = (Array.isArray(store?.getters?.columns) ? store.getters.columns : []).filter(
|
|
20
22
|
column =>
|
|
@@ -24,6 +26,9 @@ const DefaultFiltersModal = ({ storeName, visible = false, onClose }) => {
|
|
|
24
26
|
);
|
|
25
27
|
const filters = store?.getters?.filters || {};
|
|
26
28
|
const configs = store?.getters?.configs || {};
|
|
29
|
+
const [draft, setDraft] = useState(filters);
|
|
30
|
+
useEffect(() => {if (visible) setDraft({...filters});}, [visible]);
|
|
31
|
+
const activeFilters = deferred ? draft : filters;
|
|
27
32
|
const tablePreferenceScope =
|
|
28
33
|
configs.tablePreferenceScope ||
|
|
29
34
|
resolveDefaultTablePreferenceScope({ storeName });
|
|
@@ -35,6 +40,10 @@ const DefaultFiltersModal = ({ storeName, visible = false, onClose }) => {
|
|
|
35
40
|
|
|
36
41
|
persistTableFiltersPreference(tablePreferenceScope, persistedFilters);
|
|
37
42
|
|
|
43
|
+
if (deferred && typeof configs.onFilterChange === 'function') {
|
|
44
|
+
configs.onFilterChange(nextFilters);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
38
47
|
if (typeof store?.actions?.setFilters === 'function') {
|
|
39
48
|
store.actions.setFilters(nextFilters);
|
|
40
49
|
} else if (store?.getters) {
|
|
@@ -44,7 +53,7 @@ const DefaultFiltersModal = ({ storeName, visible = false, onClose }) => {
|
|
|
44
53
|
configs.onFilterChange?.(nextFilters);
|
|
45
54
|
};
|
|
46
55
|
const updateFilter = (fieldName, value) => {
|
|
47
|
-
const nextFilters = { ...(
|
|
56
|
+
const nextFilters = { ...(activeFilters || {}) };
|
|
48
57
|
const isEmpty =
|
|
49
58
|
value === null ||
|
|
50
59
|
value === undefined ||
|
|
@@ -54,12 +63,13 @@ const DefaultFiltersModal = ({ storeName, visible = false, onClose }) => {
|
|
|
54
63
|
if (isEmpty) delete nextFilters[fieldName];
|
|
55
64
|
else nextFilters[fieldName] = value;
|
|
56
65
|
|
|
57
|
-
|
|
66
|
+
if (deferred) setDraft(nextFilters);
|
|
67
|
+
else applyFilters(nextFilters);
|
|
58
68
|
};
|
|
59
|
-
const applyLabel = global.t?.t(storeName, 'button', 'apply');
|
|
60
|
-
const clearLabel = global.t?.t(storeName, 'button', 'clear');
|
|
61
|
-
const title = global.t?.t(storeName, 'label', 'filters');
|
|
62
|
-
const { modalColors, resolvedAccentColor } = useDefaultTableTheme();
|
|
69
|
+
const applyLabel = deferred ? 'Aplicar filtros' : global.t?.t(storeName, 'button', 'apply');
|
|
70
|
+
const clearLabel = deferred ? 'Limpar' : global.t?.t(storeName, 'button', 'clear');
|
|
71
|
+
const title = deferred ? 'Filtros' : global.t?.t(storeName, 'label', 'filters');
|
|
72
|
+
const { modalColors, resolvedAccentColor, themeColors } = useDefaultTableTheme();
|
|
63
73
|
if (!visible) return null;
|
|
64
74
|
|
|
65
75
|
const {
|
|
@@ -71,6 +81,21 @@ const DefaultFiltersModal = ({ storeName, visible = false, onClose }) => {
|
|
|
71
81
|
textColor,
|
|
72
82
|
} = modalColors;
|
|
73
83
|
|
|
84
|
+
if (configs.appearance === 'compact') {
|
|
85
|
+
const fields = columns.filter(column => column.compactFilter !== false);
|
|
86
|
+
const action = (label, onPress, primary = false) => <TouchableOpacity accessibilityRole="button" accessibilityLabel={label} onPress={onPress}
|
|
87
|
+
style={{minHeight: 44, justifyContent: 'center', paddingHorizontal: 18, borderRadius: 9, borderWidth: 1, borderColor, backgroundColor: primary ? themeColors.buttonBackground : themeColors.modalBackground}}>
|
|
88
|
+
<Text style={{color: primary ? themeColors.buttonText : textColor, fontSize: 14, fontWeight: '600'}}>{label}</Text>
|
|
89
|
+
</TouchableOpacity>;
|
|
90
|
+
return <DefaultCompactDialog visible title="Filtros" description="Combine os filtros e aplique para atualizar os resultados." onClose={onClose}
|
|
91
|
+
bodyHeight={fields.length * 86 + 40} footer={<>{action(clearLabel, () => setDraft({}))}{action(applyLabel, () => {applyFilters(draft); onClose?.();}, true)}</>}>
|
|
92
|
+
{fields.map(column => <View key={getColumnKey(column)} style={{gap: 8}}>
|
|
93
|
+
<Text style={{fontSize: 14, fontWeight: '600', color: textColor}}>{getCompactColumnLabel(column, formatStoreColumnLabel({columns, fieldName: getColumnKey(column), fallbackLabel: column.label || getColumnKey(column), storeName}))}</Text>
|
|
94
|
+
<DefaultColumnFilter column={column} filters={activeFilters} onChange={updateFilter} storeName={storeName} />
|
|
95
|
+
</View>)}
|
|
96
|
+
</DefaultCompactDialog>;
|
|
97
|
+
}
|
|
98
|
+
|
|
74
99
|
return (
|
|
75
100
|
<Modal visible transparent animationType="fade" onRequestClose={onClose}>
|
|
76
101
|
<View style={[styles.modalOverlay, { backgroundColor: overlayColor }]}>
|
|
@@ -80,6 +105,8 @@ const DefaultFiltersModal = ({ storeName, visible = false, onClose }) => {
|
|
|
80
105
|
{title}
|
|
81
106
|
</Text>
|
|
82
107
|
<TouchableOpacity
|
|
108
|
+
accessibilityRole="button"
|
|
109
|
+
accessibilityLabel="Fechar filtros"
|
|
83
110
|
style={[styles.modalCloseButton, { borderColor, backgroundColor }]}
|
|
84
111
|
activeOpacity={0.82}
|
|
85
112
|
onPress={onClose}
|
|
@@ -90,12 +117,13 @@ const DefaultFiltersModal = ({ storeName, visible = false, onClose }) => {
|
|
|
90
117
|
<ScrollView style={styles.filtersModalBody} contentContainerStyle={styles.filtersModalList}>
|
|
91
118
|
{columns.map(column => {
|
|
92
119
|
const fieldName = getColumnKey(column);
|
|
93
|
-
const
|
|
120
|
+
const defaultLabel = formatStoreColumnLabel({
|
|
94
121
|
columns,
|
|
95
122
|
fieldName,
|
|
96
123
|
fallbackLabel: column?.label || fieldName,
|
|
97
124
|
storeName,
|
|
98
125
|
});
|
|
126
|
+
const label = configs.appearance === 'compact' ? getCompactColumnLabel(column, defaultLabel) : defaultLabel;
|
|
99
127
|
|
|
100
128
|
return (
|
|
101
129
|
<View key={fieldName} style={styles.filtersModalField}>
|
|
@@ -104,7 +132,7 @@ const DefaultFiltersModal = ({ storeName, visible = false, onClose }) => {
|
|
|
104
132
|
</Text>
|
|
105
133
|
<DefaultColumnFilter
|
|
106
134
|
column={column}
|
|
107
|
-
filters={
|
|
135
|
+
filters={activeFilters}
|
|
108
136
|
onChange={updateFilter}
|
|
109
137
|
storeName={storeName}
|
|
110
138
|
style={styles.filtersModalInput}
|
|
@@ -115,18 +143,22 @@ const DefaultFiltersModal = ({ storeName, visible = false, onClose }) => {
|
|
|
115
143
|
</ScrollView>
|
|
116
144
|
<View style={[styles.modalActions, { borderTopColor: borderColor }]}>
|
|
117
145
|
<TouchableOpacity
|
|
146
|
+
accessibilityRole="button"
|
|
147
|
+
accessibilityLabel={clearLabel}
|
|
118
148
|
style={[styles.secondaryButton, { borderColor }]}
|
|
119
149
|
activeOpacity={0.82}
|
|
120
|
-
onPress={() => applyFilters({})}
|
|
150
|
+
onPress={() => deferred ? setDraft({}) : applyFilters({})}
|
|
121
151
|
>
|
|
122
152
|
<Text style={[styles.secondaryButtonText, { color: textColor }]}>
|
|
123
153
|
{clearLabel}
|
|
124
154
|
</Text>
|
|
125
155
|
</TouchableOpacity>
|
|
126
156
|
<TouchableOpacity
|
|
157
|
+
accessibilityRole="button"
|
|
158
|
+
accessibilityLabel={applyLabel}
|
|
127
159
|
style={[styles.primaryButton, { backgroundColor: resolvedAccentColor }]}
|
|
128
160
|
activeOpacity={0.82}
|
|
129
|
-
onPress={onClose}
|
|
161
|
+
onPress={() => {if (deferred) applyFilters(draft); onClose?.();}}
|
|
130
162
|
>
|
|
131
163
|
<Text style={styles.primaryButtonText}>
|
|
132
164
|
{applyLabel}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useEffect, useMemo, useRef } from 'react';
|
|
2
2
|
import { useWindowDimensions } from 'react-native';
|
|
3
3
|
import { NavigationRouteContext, useIsFocused } from '@react-navigation/native';
|
|
4
4
|
import { useStore } from '@store';
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
} from './useDefaultTableSorting';
|
|
17
17
|
import useDefaultTableTheme from './useDefaultTableTheme';
|
|
18
18
|
import DefaultTableView from './DefaultTableView';
|
|
19
|
+
import useDefaultTableCreateForm from './useDefaultTableCreateForm';
|
|
19
20
|
|
|
20
21
|
import {
|
|
21
22
|
assignGetterValue,
|
|
@@ -63,6 +64,8 @@ const DefaultTable = ({
|
|
|
63
64
|
onSelectionChange = null,
|
|
64
65
|
onSortChange = null,
|
|
65
66
|
pageSize = null,
|
|
67
|
+
appearance = 'default',
|
|
68
|
+
paginationMode = 'infinite',
|
|
66
69
|
pinRowActions = true,
|
|
67
70
|
renderCard = null,
|
|
68
71
|
requestParams = {},
|
|
@@ -86,7 +89,6 @@ const DefaultTable = ({
|
|
|
86
89
|
toolbarActions = [],
|
|
87
90
|
visibleColumnsPreferenceKey = '',
|
|
88
91
|
}) => {
|
|
89
|
-
const [isCreateFormOpen, setIsCreateFormOpen] = useState(false);
|
|
90
92
|
const { width } = useWindowDimensions();
|
|
91
93
|
const route = React.useContext(NavigationRouteContext);
|
|
92
94
|
const store = useStore(storeName);
|
|
@@ -94,7 +96,7 @@ const DefaultTable = ({
|
|
|
94
96
|
const isFocused = useIsFocused();
|
|
95
97
|
const storeDeclaredConfigsRef = useRef(null);
|
|
96
98
|
const { showError } = useMessage() || {};
|
|
97
|
-
const { tableBorderColors, themeColors } = useDefaultTableTheme(accentColor);
|
|
99
|
+
const { tableBorderColors, themeColors } = useDefaultTableTheme(accentColor, appearance);
|
|
98
100
|
const tablePanelBorderColor = tableBorderColors.containerBorderColor;
|
|
99
101
|
const floatingAddBackgroundColor =
|
|
100
102
|
themeColors.buttonBackground || themeColors.primary || accentColor;
|
|
@@ -165,6 +167,9 @@ const DefaultTable = ({
|
|
|
165
167
|
const {
|
|
166
168
|
buildRequestQuery,
|
|
167
169
|
currentPage,
|
|
170
|
+
pageSizeNumber,
|
|
171
|
+
goToPage,
|
|
172
|
+
resolvedIsLoading,
|
|
168
173
|
handleEndReached,
|
|
169
174
|
handleRefresh,
|
|
170
175
|
resolvedData,
|
|
@@ -180,6 +185,7 @@ const DefaultTable = ({
|
|
|
180
185
|
onEndReached,
|
|
181
186
|
onRefresh,
|
|
182
187
|
pageSize,
|
|
188
|
+
paginationMode,
|
|
183
189
|
requestParams: requestParamsSeed,
|
|
184
190
|
resolvedActions,
|
|
185
191
|
resolvedSort,
|
|
@@ -194,23 +200,10 @@ const DefaultTable = ({
|
|
|
194
200
|
storeName,
|
|
195
201
|
tableColumns: columnsForTable,
|
|
196
202
|
});
|
|
197
|
-
const closeCreateForm
|
|
198
|
-
|
|
199
|
-
const handleAdd = useCallback(() => {
|
|
200
|
-
if (typeof onAdd === 'function') {
|
|
201
|
-
return onAdd();
|
|
202
|
-
}
|
|
203
|
-
if (!canUseDefaultCreateForm) {
|
|
204
|
-
return null;
|
|
205
|
-
}
|
|
206
|
-
setIsCreateFormOpen(true);
|
|
207
|
-
return null;
|
|
208
|
-
}, [canUseDefaultCreateForm, onAdd]);
|
|
209
|
-
const resolvedOnAdd = typeof onAdd === 'function' || canUseDefaultCreateForm
|
|
210
|
-
? handleAdd
|
|
211
|
-
: null;
|
|
203
|
+
const {isCreateFormOpen, closeCreateForm, resolvedOnAdd, handleDefaultCreateSaved} =
|
|
204
|
+
useDefaultTableCreateForm({onAdd, onSaved, resolvedActions, handleRefresh});
|
|
212
205
|
const hasAddAction =
|
|
213
|
-
(addConfig === true || add === true) &&
|
|
206
|
+
add !== false && (addConfig === true || add === true) &&
|
|
214
207
|
typeof resolvedOnAdd === 'function';
|
|
215
208
|
const shouldRenderFloatingAddButton =
|
|
216
209
|
hasAddAction &&
|
|
@@ -219,14 +212,6 @@ const DefaultTable = ({
|
|
|
219
212
|
hasAddAction &&
|
|
220
213
|
showToolbar !== false &&
|
|
221
214
|
normalizedAddButtonPlacement === 'bottom';
|
|
222
|
-
const handleDefaultCreateSaved = useCallback(
|
|
223
|
-
savedItem => {
|
|
224
|
-
closeCreateForm();
|
|
225
|
-
onSaved?.(savedItem, null);
|
|
226
|
-
handleRefresh?.();
|
|
227
|
-
},
|
|
228
|
-
[closeCreateForm, handleRefresh, onSaved],
|
|
229
|
-
);
|
|
230
215
|
const debugFallbackParameters = useMemo(() => {
|
|
231
216
|
if (autoMode) {
|
|
232
217
|
return buildRequestQuery(currentPage || 1, false);
|
|
@@ -237,7 +222,11 @@ const DefaultTable = ({
|
|
|
237
222
|
sort: resolvedSort || null,
|
|
238
223
|
};
|
|
239
224
|
}, [autoMode, buildRequestQuery, currentPage, requestParamsSeed, resolvedSort, storeFilters]);
|
|
225
|
+
const previousCompactRef = useRef(isCompactView);
|
|
226
|
+
const enteringCompact = isCompactView && !previousCompactRef.current;
|
|
227
|
+
useEffect(() => {previousCompactRef.current = isCompactView;}, [isCompactView]);
|
|
240
228
|
const effectiveViewMode =
|
|
229
|
+
enteringCompact && forceCardsOnCompact !== false ? 'cards' :
|
|
241
230
|
currentConfigs.viewMode ||
|
|
242
231
|
storedViewMode ||
|
|
243
232
|
(isCompactView && forceCardsOnCompact !== false ? 'cards' : initialViewMode);
|
|
@@ -245,6 +234,12 @@ const DefaultTable = ({
|
|
|
245
234
|
const defaultTableConfigs = useMemo(
|
|
246
235
|
() => ({
|
|
247
236
|
...storeDeclaredConfigs,
|
|
237
|
+
appearance,
|
|
238
|
+
paginationMode,
|
|
239
|
+
currentPage,
|
|
240
|
+
pageSizeNumber,
|
|
241
|
+
onPageChange: goToPage,
|
|
242
|
+
paginationLoading: resolvedIsLoading,
|
|
248
243
|
add,
|
|
249
244
|
addButtonPlacement: normalizedAddButtonPlacement,
|
|
250
245
|
addLabel: resolvedAddLabel,
|
|
@@ -311,6 +306,7 @@ const DefaultTable = ({
|
|
|
311
306
|
viewMode: effectiveViewMode,
|
|
312
307
|
}),
|
|
313
308
|
[
|
|
309
|
+
appearance, paginationMode, currentPage, pageSizeNumber, goToPage, resolvedIsLoading,
|
|
314
310
|
add,
|
|
315
311
|
normalizedAddButtonPlacement,
|
|
316
312
|
resolvedAddLabel,
|
|
@@ -373,6 +369,7 @@ const DefaultTable = ({
|
|
|
373
369
|
const defaultTableConfigsSignature = useMemo(
|
|
374
370
|
() =>
|
|
375
371
|
stableSerialize({
|
|
372
|
+
appearance, paginationMode, currentPage, pageSizeNumber, resolvedIsLoading,
|
|
376
373
|
configuredImport: storeDeclaredConfigs.import || null,
|
|
377
374
|
add,
|
|
378
375
|
addButtonPlacement: normalizedAddButtonPlacement,
|
|
@@ -408,6 +405,7 @@ const DefaultTable = ({
|
|
|
408
405
|
toolbarActionsLength: Array.isArray(toolbarActions) ? toolbarActions.length : 0,
|
|
409
406
|
}),
|
|
410
407
|
[
|
|
408
|
+
appearance, paginationMode, currentPage, pageSizeNumber, goToPage, resolvedIsLoading,
|
|
411
409
|
add,
|
|
412
410
|
normalizedAddButtonPlacement,
|
|
413
411
|
resolvedAddLabel,
|
|
@@ -452,6 +450,8 @@ const DefaultTable = ({
|
|
|
452
450
|
// opening Adicionar on DefaultTable (categories). Sync only in the hook
|
|
453
451
|
// when defaultTableConfigsSignature changes.
|
|
454
452
|
useDefaultTableStoreSync({
|
|
453
|
+
filters,
|
|
454
|
+
onFilterChange,
|
|
455
455
|
columns,
|
|
456
456
|
columnsForTable,
|
|
457
457
|
data,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { FlatList, Text, View } from 'react-native';
|
|
1
|
+
import React, {useState} from 'react';
|
|
2
|
+
import { FlatList, Text, View, useWindowDimensions } from 'react-native';
|
|
3
3
|
import { useStore } from '@store';
|
|
4
4
|
import { formatStoreColumnLabel } from '@controleonline/ui-common/src/react/utils/storeColumns';
|
|
5
5
|
import { getColumnKey, resolveCellText } from '../inputs/defaultInputUtils';
|
|
@@ -16,12 +16,25 @@ import {
|
|
|
16
16
|
shouldIncludeColumn,
|
|
17
17
|
} from './DefaultTable.utils';
|
|
18
18
|
import styles from './DefaultTable.styles';
|
|
19
|
+
import compactStyles from './DefaultTableCompact.styles';
|
|
20
|
+
import useDefaultTableRowInteraction from './useDefaultTableRowInteraction';
|
|
19
21
|
import useDefaultTableTheme from './useDefaultTableTheme';
|
|
20
22
|
|
|
21
23
|
// Vertical cards must keep their intrinsic height; zero basis is only for grid rows.
|
|
22
24
|
const intrinsicHeight = {flexBasis: 'auto', flexGrow: 0, flexShrink: 0};
|
|
23
25
|
|
|
26
|
+
/** Responsive card grid (OrderHistory / compact lists). Explicit cardListProps.numColumns wins. */
|
|
27
|
+
export const resolveResponsiveCardColumns = width => {
|
|
28
|
+
const w = Number(width) || 0;
|
|
29
|
+
if (w >= 1280) return 3;
|
|
30
|
+
if (w >= 800) return 2;
|
|
31
|
+
return 1;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
|
|
24
35
|
const DefaultTableCards = ({ storeName }) => {
|
|
36
|
+
const [listWidth, setListWidth] = useState(0);
|
|
37
|
+
const {canOpenRow, setRowInteraction} = useDefaultTableRowInteraction();
|
|
25
38
|
const store = useStore(storeName);
|
|
26
39
|
const configs = store?.getters?.configs || {};
|
|
27
40
|
const { palette } = useDefaultTableTheme();
|
|
@@ -38,10 +51,21 @@ const DefaultTableCards = ({ storeName }) => {
|
|
|
38
51
|
configs.cardListProps && typeof configs.cardListProps === 'object'
|
|
39
52
|
? configs.cardListProps
|
|
40
53
|
: {};
|
|
54
|
+
const compact = configs.appearance === 'compact';
|
|
55
|
+
const {width: windowWidth} = useWindowDimensions();
|
|
56
|
+
const explicitNumColumns = Number(cardListProps.numColumns);
|
|
57
|
+
const hasExplicitNumColumns = Number.isFinite(explicitNumColumns) && explicitNumColumns > 0;
|
|
58
|
+
// Default responsive grid for all card tables (same breakpoints as OrderHistory).
|
|
59
|
+
// Callers may still force a fixed column count via cardListProps.numColumns.
|
|
60
|
+
const gridColumns = hasExplicitNumColumns
|
|
61
|
+
? explicitNumColumns
|
|
62
|
+
: resolveResponsiveCardColumns(windowWidth);
|
|
63
|
+
const compactCardWidth = listWidth ? Math.max(0, (listWidth - 24 - 12 * (gridColumns - 1)) / gridColumns) : undefined;
|
|
41
64
|
const {
|
|
42
65
|
contentContainerStyle,
|
|
43
66
|
key: cardListKey,
|
|
44
67
|
listKey,
|
|
68
|
+
numColumns: _ignoredNumColumns,
|
|
45
69
|
...flatListProps
|
|
46
70
|
} = cardListProps;
|
|
47
71
|
const isLoading = Boolean(store?.getters?.isLoadingList || store?.getters?.isLoading);
|
|
@@ -67,7 +91,7 @@ const DefaultTableCards = ({ storeName }) => {
|
|
|
67
91
|
const renderField = (fieldName, options = {}) => (
|
|
68
92
|
<DefaultTableInput
|
|
69
93
|
fieldName={fieldName}
|
|
70
|
-
options={options}
|
|
94
|
+
options={{...options, onInteractionChange: blocked => {options.onInteractionChange?.(blocked); setRowInteraction(row, {key: fieldName}, blocked);}}}
|
|
71
95
|
row={row}
|
|
72
96
|
storeName={storeName}
|
|
73
97
|
variant="card"
|
|
@@ -89,10 +113,10 @@ const DefaultTableCards = ({ storeName }) => {
|
|
|
89
113
|
component={RowActionsComponent}
|
|
90
114
|
helpers={{
|
|
91
115
|
openEdit: () => configs.onEditRow?.(row),
|
|
92
|
-
openRow: hasRowPress ? () => configs.onRowPress(row) : null,
|
|
116
|
+
openRow: hasRowPress ? () => {if (canOpenRow(row)) configs.onRowPress(row);} : null,
|
|
93
117
|
}}
|
|
94
118
|
openEdit={() => configs.onEditRow?.(row)}
|
|
95
|
-
openRow={hasRowPress ? () => configs.onRowPress(row) : null}
|
|
119
|
+
openRow={hasRowPress ? () => {if (canOpenRow(row)) configs.onRowPress(row);} : null}
|
|
96
120
|
row={row}
|
|
97
121
|
storeName={storeName}
|
|
98
122
|
/>
|
|
@@ -109,23 +133,24 @@ const DefaultTableCards = ({ storeName }) => {
|
|
|
109
133
|
key={row?.['@id'] || row?.id}
|
|
110
134
|
style={[
|
|
111
135
|
styles.cardItem,
|
|
112
|
-
|
|
136
|
+
gridColumns === 1 ? intrinsicHeight : null,
|
|
113
137
|
hasRowActions ? styles.cardItemWithActions : null,
|
|
114
138
|
rowStyleValue,
|
|
139
|
+
compact ? [compactStyles.cardItem, {flex: 0, flexGrow: 0, flexShrink: 0, flexBasis: 'auto', width: compactCardWidth, maxWidth: compactCardWidth, backgroundColor: palette.cardBackground || palette.panelBackground, borderColor: palette.cardBorder || palette.inputBorder}] : null,
|
|
115
140
|
]}
|
|
116
141
|
>
|
|
117
|
-
<View style={[styles.cardContent, hasRowActions ? null : intrinsicHeight]}>
|
|
142
|
+
<View style={[styles.cardContent, hasRowActions ? null : intrinsicHeight, compact ? {flex: 0, flexBasis: 'auto', flexGrow: 0} : null]}>
|
|
118
143
|
{configs.renderCard({
|
|
119
144
|
item: row,
|
|
120
145
|
openEdit: () => configs.onEditRow?.(row),
|
|
121
|
-
openRow: hasRowPress ? () => configs.onRowPress(row) : null,
|
|
146
|
+
openRow: hasRowPress ? () => {if (canOpenRow(row)) configs.onRowPress(row);} : null,
|
|
122
147
|
renderField,
|
|
123
148
|
renderValue,
|
|
124
149
|
row,
|
|
125
150
|
})}
|
|
126
151
|
</View>
|
|
127
152
|
{hasRowActions ? (
|
|
128
|
-
<View style={styles.cardActions}>
|
|
153
|
+
<View style={compact ? [compactStyles.cardActions, {backgroundColor: palette.tableFooterBackground, borderTopColor: palette.border}] : styles.cardActions}>
|
|
129
154
|
{customRowActions}
|
|
130
155
|
{editButton}
|
|
131
156
|
</View>
|
|
@@ -173,10 +198,18 @@ const DefaultTableCards = ({ storeName }) => {
|
|
|
173
198
|
);
|
|
174
199
|
};
|
|
175
200
|
|
|
201
|
+
// RN FlatList throws if numColumns changes without remount. Always derive key from numColumns
|
|
202
|
+
// and apply it AFTER the spread so callers cannot override it with a stale key.
|
|
203
|
+
const resolvedNumColumns = gridColumns;
|
|
204
|
+
const resolvedListKey = listKey || cardListKey || `cards-${resolvedNumColumns}`;
|
|
205
|
+
|
|
176
206
|
return (
|
|
177
207
|
<FlatList
|
|
178
|
-
key={listKey || cardListKey || `cards-${flatListProps.numColumns || 1}`}
|
|
179
208
|
{...flatListProps}
|
|
209
|
+
key={resolvedListKey}
|
|
210
|
+
numColumns={resolvedNumColumns}
|
|
211
|
+
onLayout={event => {flatListProps.onLayout?.(event); setListWidth(event.nativeEvent.layout.width);}}
|
|
212
|
+
columnWrapperStyle={compact && gridColumns > 1 ? {gap: 12} : flatListProps.columnWrapperStyle}
|
|
180
213
|
data={sortedData}
|
|
181
214
|
keyExtractor={getRowKey}
|
|
182
215
|
renderItem={({ item, index }) => renderCardItem(item, index)}
|
|
@@ -184,6 +217,7 @@ const DefaultTableCards = ({ storeName }) => {
|
|
|
184
217
|
contentContainerStyle={[
|
|
185
218
|
styles.cardsGrid,
|
|
186
219
|
contentContainerStyle,
|
|
220
|
+
compact ? {padding: 12, gap: 12} : null,
|
|
187
221
|
hasBottomAddButton ? styles.cardsGridWithBottomAdd : null,
|
|
188
222
|
]}
|
|
189
223
|
ListEmptyComponent={(
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export const isActiveTableFilter = value => {
|
|
2
|
+
if (value === null || value === undefined || value === '') return false;
|
|
3
|
+
if (Array.isArray(value)) return value.length > 0;
|
|
4
|
+
if (typeof value === 'object') {
|
|
5
|
+
if (value.shortcut) return value.shortcut !== 'all';
|
|
6
|
+
if ('value' in value) return isActiveTableFilter(value.value);
|
|
7
|
+
return Object.values(value).some(isActiveTableFilter);
|
|
8
|
+
}
|
|
9
|
+
return true;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const getCompactFilterLabel = value => {
|
|
13
|
+
if (Array.isArray(value)) return value.map(getCompactFilterLabel).join(', ');
|
|
14
|
+
if (value && typeof value === 'object') {
|
|
15
|
+
if (value.shortcut) return ({today: 'Hoje', yesterday: 'Ontem', all: 'Todos', custom: 'Personalizado'})[value.shortcut] || value.shortcut;
|
|
16
|
+
return String(value.label || value.value || 'Selecionado');
|
|
17
|
+
}
|
|
18
|
+
return String(value ?? '');
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const getVisiblePageNumbers = (page, totalPages) => {
|
|
22
|
+
const start = Math.max(1, Math.min(page - 1, totalPages - 2));
|
|
23
|
+
return Array.from({length: Math.min(3, totalPages)}, (_, index) => start + index);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const getCompactColumnLabel = (column, fallback) => column?.compactLabel || fallback;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {StyleSheet} from 'react-native';
|
|
2
|
+
|
|
3
|
+
export default StyleSheet.create({
|
|
4
|
+
toolbar: {padding: 12, gap: 8, borderBottomWidth: 1, flexShrink: 0},
|
|
5
|
+
row: {flexDirection: 'row', alignItems: 'center', flexWrap: 'wrap', gap: 8},
|
|
6
|
+
search: {flex: 1, maxWidth: 620, minWidth: 210, flexDirection: 'row', alignItems: 'center', gap: 8, borderWidth: 1, borderRadius: 8, paddingHorizontal: 10},
|
|
7
|
+
searchMobile: {flexBasis: '100%', maxWidth: '100%', minWidth: 0},
|
|
8
|
+
input: {flex: 1, minWidth: 0, height: 42, fontSize: 14},
|
|
9
|
+
inputMobile: {fontSize: 16},
|
|
10
|
+
button: {minHeight: 44, minWidth: 44, paddingHorizontal: 10, borderWidth: 1, borderRadius: 8, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 6},
|
|
11
|
+
label: {fontSize: 12, fontWeight: '600'},
|
|
12
|
+
small: {fontSize: 12},
|
|
13
|
+
chips: {flexDirection: 'row', flexWrap: 'wrap', gap: 6, alignItems: 'center'},
|
|
14
|
+
chip: {minHeight: 30, maxWidth: '100%', borderWidth: 1, borderRadius: 18, paddingHorizontal: 9, flexDirection: 'row', alignItems: 'center', gap: 6},
|
|
15
|
+
secondary: {flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', flexWrap: 'wrap', gap: 8},
|
|
16
|
+
mode: {flexDirection: 'row', gap: 3},
|
|
17
|
+
backdrop: {flex: 1, alignItems: 'center', justifyContent: 'center', padding: 16},
|
|
18
|
+
sheet: {width: '100%', maxWidth: 480, maxHeight: '85%', borderWidth: 1, borderRadius: 14, padding: 16, gap: 12},
|
|
19
|
+
sheetHeader: {flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', gap: 10},
|
|
20
|
+
sheetTitle: {fontSize: 17, fontWeight: '600'},
|
|
21
|
+
option: {minHeight: 44, paddingVertical: 10, flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', gap: 8},
|
|
22
|
+
footer: {padding: 10, flexShrink: 0, borderTopWidth: 1, flexDirection: 'row', flexWrap: 'wrap', alignItems: 'center', justifyContent: 'space-between', gap: 8},
|
|
23
|
+
pager: {flexDirection: 'row', flexWrap: 'wrap', gap: 4, alignItems: 'center'},
|
|
24
|
+
page: {minWidth: 44, minHeight: 44, borderWidth: 1, borderRadius: 7, justifyContent: 'center', alignItems: 'center'},
|
|
25
|
+
disabled: {opacity: 0.45},
|
|
26
|
+
cardItem: {flexDirection: 'column', alignItems: 'stretch', borderWidth: 1, borderRadius: 12, overflow: 'hidden', margin: 0},
|
|
27
|
+
cardActions: {alignSelf: 'stretch', flexDirection: 'row', justifyContent: 'flex-end', borderTopWidth: 1, paddingHorizontal: 12, paddingVertical: 8},
|
|
28
|
+
});
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import React, {useEffect, useState} from 'react';
|
|
2
|
+
import {Text, TextInput, TouchableOpacity, View, useWindowDimensions} 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 {getSortField, isSortableColumn} from './DefaultTable.utils';
|
|
8
|
+
import {persistTableFiltersPreference, persistTableViewModePreference} from '../../utils/tableVisibleColumnsPreferences';
|
|
9
|
+
import DefaultCompactDialog from './DefaultCompactDialog';
|
|
10
|
+
import DefaultFiltersModal from './DefaultFiltersModal';
|
|
11
|
+
import DefaultColumnMenu from './DefaultColumnMenu';
|
|
12
|
+
import DefaultDebug from './DefaultDebug';
|
|
13
|
+
import DefaultToolbarAction from './DefaultToolbarAction';
|
|
14
|
+
import useDefaultTableTheme from './useDefaultTableTheme';
|
|
15
|
+
import {getCompactColumnLabel, getCompactFilterLabel, isActiveTableFilter} from './DefaultTableCompact.helpers';
|
|
16
|
+
import s from './DefaultTableCompact.styles';
|
|
17
|
+
|
|
18
|
+
export default function DefaultTableCompactToolbar({storeName, actions = [], showControls = true}) {
|
|
19
|
+
const store = useStore(storeName);
|
|
20
|
+
const configs = store?.getters?.configs || {};
|
|
21
|
+
const filters = store?.getters?.filters || {};
|
|
22
|
+
const columns = store?.getters?.columns || [];
|
|
23
|
+
const {themeColors: c} = useDefaultTableTheme();
|
|
24
|
+
const {width} = useWindowDimensions();
|
|
25
|
+
const mobile = width <= (configs.compactBreakpoint || 768);
|
|
26
|
+
const [modal, setModal] = useState('');
|
|
27
|
+
const searchKey = configs.searchKey || 'search';
|
|
28
|
+
const [draft, setDraft] = useState(String(filters[searchKey] || ''));
|
|
29
|
+
useEffect(() => setDraft(String(filters[searchKey] || '')), [filters[searchKey]]);
|
|
30
|
+
const entries = Object.entries(filters).filter(([, value]) => isActiveTableFilter(value));
|
|
31
|
+
const text = c.textPrimary || c.text;
|
|
32
|
+
const muted = c.textSecondary || text;
|
|
33
|
+
const panel = c.panelBackground || c.cardBackground || c.appBackground;
|
|
34
|
+
const border = c.inputBorder || c.cardBorder || c.border;
|
|
35
|
+
const apply = next => {
|
|
36
|
+
persistTableFiltersPreference(configs.tablePreferenceScope, next);
|
|
37
|
+
if (configs.onFilterChange) configs.onFilterChange(next);
|
|
38
|
+
else store.actions?.setFilters?.(next);
|
|
39
|
+
};
|
|
40
|
+
const remove = key => {const next = {...filters}; delete next[key]; apply(next);};
|
|
41
|
+
const submit = () => {const next = {...filters}; if (draft.trim()) next[searchKey] = draft.trim(); else delete next[searchKey]; apply(next);};
|
|
42
|
+
const button = (label, icon, onPress, selected = false, primary = false) => (
|
|
43
|
+
<TouchableOpacity accessibilityRole="button" accessibilityLabel={label} accessibilityState={{selected}} onPress={onPress}
|
|
44
|
+
style={[s.button, {backgroundColor: primary ? c.buttonBackground : selected ? c.chipSelectedBackground || panel : panel, borderColor: border}, !mobile && icon === 'sliders' ? {marginLeft: 'auto'} : null]}>
|
|
45
|
+
<Icon name={icon} size={16} color={primary ? c.buttonIcon || c.buttonText : text} />
|
|
46
|
+
{label && (!mobile || width >= 360 && (label === 'Filtros' || primary)) ? <Text style={[s.label, {color: primary ? c.buttonText : text}]}>{primary && mobile ? 'Novo' : label}</Text> : null}
|
|
47
|
+
</TouchableOpacity>
|
|
48
|
+
);
|
|
49
|
+
const mode = configs.effectiveViewMode || 'table';
|
|
50
|
+
const setMode = value => {
|
|
51
|
+
persistTableViewModePreference(configs.tablePreferenceScope, value);
|
|
52
|
+
store.actions?.setConfigs?.({...configs, effectiveViewMode: value, viewMode: value});
|
|
53
|
+
};
|
|
54
|
+
const canAdd = configs.add !== false && (configs.add === true || store.getters?.add === true) && configs.onAdd;
|
|
55
|
+
const buttonLabel = configs.addLabel || 'Novo pedido';
|
|
56
|
+
const columnButton = () => button('Colunas', 'columns', () => setModal('columns'));
|
|
57
|
+
const addButton = () => button(buttonLabel, 'plus', configs.onAdd, false, true);
|
|
58
|
+
const sortColumn = columns.find(column => getSortField(column) === configs.resolvedSort?.field);
|
|
59
|
+
const labelFor = column => getCompactColumnLabel(column, formatStoreColumnLabel({columns, fieldName: getColumnKey(column), fallbackLabel: column?.label || getColumnKey(column), storeName}));
|
|
60
|
+
return (
|
|
61
|
+
<View style={[s.toolbar, {backgroundColor: c.toolbarBackground || panel, borderBottomColor: border}]}>
|
|
62
|
+
<View style={[s.row, {gap: mobile ? 6 : 8}]}>
|
|
63
|
+
{configs.showSearch !== false ? <View style={[s.search, mobile && s.searchMobile, {borderColor: border, backgroundColor: c.inputBackground || panel}]}>
|
|
64
|
+
<Icon name="search" size={16} color={c.inputIcon || muted} />
|
|
65
|
+
<TextInput accessibilityLabel={configs.searchPlaceholder || 'Buscar'} placeholder={configs.searchPlaceholder || 'Buscar'} placeholderTextColor={c.inputPlaceholderText || muted}
|
|
66
|
+
value={draft} onChangeText={setDraft} onSubmitEditing={submit} returnKeyType="search" style={[s.input, mobile && s.inputMobile, {color: c.inputText || text}]} />
|
|
67
|
+
<TouchableOpacity accessibilityRole="button" accessibilityLabel="Pesquisar" onPress={submit} style={{padding: 8}}><Icon name="arrow-right" size={16} color={text} /></TouchableOpacity>
|
|
68
|
+
</View> : null}
|
|
69
|
+
{showControls ? <>
|
|
70
|
+
{button('Filtros', 'sliders', () => setModal('filters'))}
|
|
71
|
+
<View style={s.mode}>{button('Tabela', 'list', () => setMode('table'), mode === 'table')}{button('Cards', 'grid', () => setMode('cards'), mode === 'cards')}</View>
|
|
72
|
+
{!mobile ? columnButton() : null}
|
|
73
|
+
{button('Mais opções', 'more-horizontal', () => setModal('more'))}
|
|
74
|
+
{canAdd ? addButton() : null}
|
|
75
|
+
</> : null}
|
|
76
|
+
</View>
|
|
77
|
+
{entries.length ? <View style={s.chips}>{entries.map(([key, value]) => {
|
|
78
|
+
const column = columns.find(item => getColumnKey(item) === key);
|
|
79
|
+
const options = column ? configs.getOptionsForColumn?.(column) || column.options || [] : [];
|
|
80
|
+
const valueLabel = Array.isArray(options) ? (Array.isArray(value) ? value : [value]).map(item => options.find(option => String(option.value ?? option.key) === String(item))?.label || getCompactFilterLabel(item)).join(', ') : getCompactFilterLabel(value);
|
|
81
|
+
const label = `${column ? labelFor(column) + ': ' : key === searchKey ? 'Busca: ' : key + ': '}${valueLabel}`;
|
|
82
|
+
return <TouchableOpacity key={key} accessibilityRole="button" accessibilityLabel={`Remover filtro ${label}`} onPress={() => remove(key)} style={[s.chip, {borderColor: border, backgroundColor: c.chipBackground || panel}]}>
|
|
83
|
+
<Text numberOfLines={1} style={[s.small, {color: c.chipText || text, flexShrink: 1}]}>{label}</Text><Icon name="x" size={12} color={text} />
|
|
84
|
+
</TouchableOpacity>;
|
|
85
|
+
})}<TouchableOpacity accessibilityRole="button" onPress={() => apply({})}><Text style={[s.small, {color: muted}]}>Limpar filtros</Text></TouchableOpacity></View> : null}
|
|
86
|
+
<View style={s.secondary}>
|
|
87
|
+
<Text style={[s.small, {color: muted}]}>{configs.showTotalItemsInFooter !== false ? `${store.getters?.totalItems ?? 0} ${Number(store.getters?.totalItems) === 1 ? 'resultado' : 'resultados'}` : 'Pedidos'}</Text>
|
|
88
|
+
{showControls ? <TouchableOpacity accessibilityRole="button" accessibilityLabel="Escolher ordenação" onPress={() => setModal('sort')} style={s.row}>
|
|
89
|
+
<Icon name="arrow-down" size={14} color={muted} /><Text style={[s.small, {color: text}]}>{sortColumn ? labelFor(sortColumn) : 'Ordenar'} · {configs.resolvedSort?.direction === 'asc' ? '↑' : '↓'}</Text>
|
|
90
|
+
</TouchableOpacity> : null}
|
|
91
|
+
</View>
|
|
92
|
+
<DefaultFiltersModal storeName={storeName} visible={modal === 'filters'} deferred onClose={() => setModal('')} />
|
|
93
|
+
<DefaultColumnMenu storeName={storeName} visible={modal === 'columns'} onClose={() => setModal('')} />
|
|
94
|
+
<DefaultCompactDialog visible={modal === 'more' || modal === 'sort'} title={modal === 'sort' ? 'Ordenação' : 'Mais opções'}
|
|
95
|
+
description={modal === 'sort' ? 'Escolha a coluna. Toque novamente para inverter a ordem.' : undefined}
|
|
96
|
+
onClose={() => setModal('')} bodyHeight={modal === 'sort' ? columns.filter(isSortableColumn).length * 54 + 32 : 180}>
|
|
97
|
+
{modal === 'sort' ? columns.filter(isSortableColumn).map(column => <TouchableOpacity key={getColumnKey(column)} accessibilityRole="button"
|
|
98
|
+
accessibilityLabel={`Ordenar por ${labelFor(column)}`} style={[s.option, {borderBottomWidth: 1, borderBottomColor: c.tableRowBorder}]}
|
|
99
|
+
onPress={() => {configs.requestSort?.(column); setModal('');}}>
|
|
100
|
+
<Text style={{color: text, fontSize: 14}}>{labelFor(column)}</Text><Text style={{color: muted}}>{getSortField(column) === configs.resolvedSort?.field ? configs.resolvedSort.direction === 'asc' ? '↑' : '↓' : '↕'}</Text>
|
|
101
|
+
</TouchableOpacity>) : <View style={{gap: 8}}>{mobile ? <DefaultToolbarAction action={{label: 'Colunas visíveis', icon: 'columns', onPress: () => setModal('columns'), color: text,
|
|
102
|
+
style: {width: '100%', minHeight: 48, justifyContent: 'flex-start', paddingHorizontal: 12, borderWidth: 0, backgroundColor: c.inputBackground}, labelStyle: {fontSize: 14}}} /> : null}
|
|
103
|
+
{actions.filter(action => !action.hidden).map(action => <DefaultToolbarAction key={action.key || action.icon}
|
|
104
|
+
action={{...action, label: action.label || action.accessibilityLabel, color: text,
|
|
105
|
+
style: {width: '100%', minHeight: 48, justifyContent: 'flex-start', paddingHorizontal: 12, borderWidth: 0, backgroundColor: c.inputBackground}, labelStyle: {fontSize: 14, fontWeight: '400'},
|
|
106
|
+
onPress: () => {setModal(''); action.onPress?.();}}} />)}
|
|
107
|
+
<DefaultDebug storeName={storeName} />
|
|
108
|
+
</View>}
|
|
109
|
+
</DefaultCompactDialog>
|
|
110
|
+
</View>
|
|
111
|
+
);
|
|
112
|
+
}
|