@controleonline/ui-default 1.0.263 → 1.0.265
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/AGENTS.md +47 -45
- package/package.json +20 -20
- package/src/react/components/errors/DefaultErrors.js +307 -325
- package/src/react/components/files/DefaultFile.js +46 -46
- package/src/react/components/filters/CompactFilterSelector.js +78 -24
- package/src/react/components/filters/CompactFilterSelector.styles.js +17 -5
- package/src/react/components/filters/DefaultColumnFilter.js +191 -57
- package/src/react/components/filters/DefaultExternalFilters.js +245 -182
- package/src/react/components/filters/DefaultSearch.js +131 -92
- package/src/react/components/filters/DefaultSearch.styles.js +65 -70
- package/src/react/components/form/DefaultForm.js +172 -151
- package/src/react/components/form/DefaultForm.styles.js +71 -66
- package/src/react/components/help/DefaultTooltip.js +87 -87
- package/src/react/components/help/DefaultTooltip.styles.js +61 -61
- package/src/react/components/inputs/DefaultDateInput.js +150 -0
- package/src/react/components/inputs/DefaultInput.js +162 -127
- package/src/react/components/inputs/DefaultInput.styles.js +6 -0
- package/src/react/components/inputs/DefaultSelect.js +320 -152
- package/src/react/components/inputs/defaultInputUtils.js +40 -19
- package/src/react/components/map/DefaultGoogleMap.styles.js +115 -9
- package/src/react/components/map/DefaultGoogleMap.web.js +560 -446
- package/src/react/components/map/DefaultMap.native.js +73 -71
- package/src/react/components/map/DefaultMap.styles.js +16 -16
- package/src/react/components/map/DefaultMap.web.js +68 -66
- package/src/react/components/map/DefaultNativeMap.native.js +307 -183
- package/src/react/components/map/DefaultNativeMap.shared.js +439 -340
- package/src/react/components/map/DefaultNativeMap.styles.js +156 -122
- package/src/react/components/table/DefaultColumnMenu.js +108 -0
- package/src/react/components/table/DefaultDebug.js +233 -0
- package/src/react/components/table/DefaultFiltersModal.js +142 -0
- package/src/react/components/table/DefaultModalButton.js +18 -0
- package/src/react/components/table/DefaultSearchModal.js +49 -0
- package/src/react/components/table/DefaultTable.js +345 -1846
- package/src/react/components/table/DefaultTable.styles.js +247 -136
- package/src/react/components/table/DefaultTable.utils.js +502 -0
- package/src/react/components/table/DefaultTableBody.js +26 -0
- package/src/react/components/table/DefaultTableCards.js +171 -0
- package/src/react/components/table/DefaultTableControls.js +208 -0
- package/src/react/components/table/DefaultTableEmptyState.js +22 -0
- package/src/react/components/table/DefaultTableFooter.js +172 -0
- package/src/react/components/table/DefaultTableInput.js +145 -0
- package/src/react/components/table/DefaultTableRows.js +340 -0
- package/src/react/components/table/DefaultTableSearch.js +100 -0
- package/src/react/components/table/DefaultTableToolbar.js +98 -0
- package/src/react/components/table/DefaultToolbarAction.js +56 -0
- package/src/react/components/table/useDefaultTablePagination.js +370 -0
- package/src/react/components/table/useDefaultTableSorting.js +126 -0
- package/src/react/components/table/useDefaultTableTheme.js +58 -0
- package/src/react/index.js +10 -10
- package/src/react/utils/tableVisibleColumnsPreferences.js +239 -211
- package/src/store/default/actions.js +51 -13
- package/src/store/default/getters.js +10 -8
- package/src/store/default/mutation_types.js +4 -2
- package/src/store/default/mutations.js +10 -1
- package/src/tests/react/components/errors/DefaultErrors.test.js +162 -162
- package/src/tests/react/components/files/DefaultFile.test.js +80 -80
- package/src/tests/react/components/form/DefaultForm.test.js +81 -0
- package/src/tests/react/components/inputs/DefaultSelect.test.js +185 -0
- package/src/tests/react/components/table/DefaultTable.test.js +1183 -0
- package/src/tests/react/store/defaultActions.test.js +59 -0
- package/src/tests/react/utils/tableVisibleColumnsPreferences.test.js +247 -168
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Modal, 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 DefaultColumnFilter from '../filters/DefaultColumnFilter';
|
|
7
|
+
import { getColumnKey, normalizeText } from '../inputs/defaultInputUtils';
|
|
8
|
+
import styles from './DefaultTable.styles';
|
|
9
|
+
import { shouldIncludeColumn } from './DefaultTable.utils';
|
|
10
|
+
import {
|
|
11
|
+
persistTableFiltersPreference,
|
|
12
|
+
resolveDefaultTablePreferenceScope,
|
|
13
|
+
sanitizeTableFiltersPreference,
|
|
14
|
+
} from '../../utils/tableVisibleColumnsPreferences';
|
|
15
|
+
import useDefaultTableTheme from './useDefaultTableTheme';
|
|
16
|
+
|
|
17
|
+
const DefaultFiltersModal = ({ storeName, visible = false, onClose }) => {
|
|
18
|
+
const store = useStore(storeName);
|
|
19
|
+
const columns = (Array.isArray(store?.getters?.columns) ? store.getters.columns : []).filter(
|
|
20
|
+
column =>
|
|
21
|
+
shouldIncludeColumn(column) &&
|
|
22
|
+
column?.filter !== false &&
|
|
23
|
+
column?.filters !== false,
|
|
24
|
+
);
|
|
25
|
+
const filters = store?.getters?.filters || {};
|
|
26
|
+
const configs = store?.getters?.configs || {};
|
|
27
|
+
const tablePreferenceScope =
|
|
28
|
+
configs.tablePreferenceScope ||
|
|
29
|
+
resolveDefaultTablePreferenceScope({ storeName });
|
|
30
|
+
const applyFilters = nextFilters => {
|
|
31
|
+
const persistedFilters = sanitizeTableFiltersPreference({
|
|
32
|
+
columns,
|
|
33
|
+
filters: nextFilters,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
persistTableFiltersPreference(tablePreferenceScope, persistedFilters);
|
|
37
|
+
|
|
38
|
+
if (typeof store?.actions?.setFilters === 'function') {
|
|
39
|
+
store.actions.setFilters(nextFilters);
|
|
40
|
+
} else if (store?.getters) {
|
|
41
|
+
store.getters.filters = nextFilters;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
configs.onFilterChange?.(nextFilters);
|
|
45
|
+
};
|
|
46
|
+
const updateFilter = (fieldName, value) => {
|
|
47
|
+
const nextFilters = { ...(filters || {}) };
|
|
48
|
+
const isEmpty =
|
|
49
|
+
value === null ||
|
|
50
|
+
value === undefined ||
|
|
51
|
+
normalizeText(value) === '' ||
|
|
52
|
+
(Array.isArray(value) && value.length === 0);
|
|
53
|
+
|
|
54
|
+
if (isEmpty) delete nextFilters[fieldName];
|
|
55
|
+
else nextFilters[fieldName] = value;
|
|
56
|
+
|
|
57
|
+
applyFilters(nextFilters);
|
|
58
|
+
};
|
|
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();
|
|
63
|
+
if (!visible) return null;
|
|
64
|
+
|
|
65
|
+
const {
|
|
66
|
+
backgroundColor,
|
|
67
|
+
borderColor,
|
|
68
|
+
closeIconColor,
|
|
69
|
+
headerTextColor,
|
|
70
|
+
overlayColor,
|
|
71
|
+
textColor,
|
|
72
|
+
} = modalColors;
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<Modal visible transparent animationType="fade" onRequestClose={onClose}>
|
|
76
|
+
<View style={[styles.modalOverlay, { backgroundColor: overlayColor }]}>
|
|
77
|
+
<View style={[styles.modalCard, styles.filtersModalCard, { borderColor, backgroundColor }]}>
|
|
78
|
+
<View style={[styles.modalHeader, { borderBottomColor: borderColor }]}>
|
|
79
|
+
<Text style={[styles.modalTitle, { color: headerTextColor }]} numberOfLines={1}>
|
|
80
|
+
{title}
|
|
81
|
+
</Text>
|
|
82
|
+
<TouchableOpacity
|
|
83
|
+
style={[styles.modalCloseButton, { borderColor, backgroundColor }]}
|
|
84
|
+
activeOpacity={0.82}
|
|
85
|
+
onPress={onClose}
|
|
86
|
+
>
|
|
87
|
+
<Icon name="x" size={16} color={closeIconColor} />
|
|
88
|
+
</TouchableOpacity>
|
|
89
|
+
</View>
|
|
90
|
+
<ScrollView style={styles.filtersModalBody} contentContainerStyle={styles.filtersModalList}>
|
|
91
|
+
{columns.map(column => {
|
|
92
|
+
const fieldName = getColumnKey(column);
|
|
93
|
+
const label = formatStoreColumnLabel({
|
|
94
|
+
columns,
|
|
95
|
+
fieldName,
|
|
96
|
+
fallbackLabel: column?.label || fieldName,
|
|
97
|
+
storeName,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<View key={fieldName} style={styles.filtersModalField}>
|
|
102
|
+
<Text style={[styles.formLabel, { color: textColor }]} numberOfLines={1}>
|
|
103
|
+
{label}
|
|
104
|
+
</Text>
|
|
105
|
+
<DefaultColumnFilter
|
|
106
|
+
column={column}
|
|
107
|
+
filters={filters}
|
|
108
|
+
onChange={updateFilter}
|
|
109
|
+
storeName={storeName}
|
|
110
|
+
style={styles.filtersModalInput}
|
|
111
|
+
/>
|
|
112
|
+
</View>
|
|
113
|
+
);
|
|
114
|
+
})}
|
|
115
|
+
</ScrollView>
|
|
116
|
+
<View style={[styles.modalActions, { borderTopColor: borderColor }]}>
|
|
117
|
+
<TouchableOpacity
|
|
118
|
+
style={[styles.secondaryButton, { borderColor }]}
|
|
119
|
+
activeOpacity={0.82}
|
|
120
|
+
onPress={() => applyFilters({})}
|
|
121
|
+
>
|
|
122
|
+
<Text style={[styles.secondaryButtonText, { color: textColor }]}>
|
|
123
|
+
{clearLabel}
|
|
124
|
+
</Text>
|
|
125
|
+
</TouchableOpacity>
|
|
126
|
+
<TouchableOpacity
|
|
127
|
+
style={[styles.primaryButton, { backgroundColor: resolvedAccentColor }]}
|
|
128
|
+
activeOpacity={0.82}
|
|
129
|
+
onPress={onClose}
|
|
130
|
+
>
|
|
131
|
+
<Text style={styles.primaryButtonText}>
|
|
132
|
+
{applyLabel}
|
|
133
|
+
</Text>
|
|
134
|
+
</TouchableOpacity>
|
|
135
|
+
</View>
|
|
136
|
+
</View>
|
|
137
|
+
</View>
|
|
138
|
+
</Modal>
|
|
139
|
+
);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export default DefaultFiltersModal;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React, { useCallback, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
const DefaultModalButton = ({ children, renderButton }) => {
|
|
4
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
5
|
+
|
|
6
|
+
const close = useCallback(() => setIsOpen(false), []);
|
|
7
|
+
const open = useCallback(() => setIsOpen(true), []);
|
|
8
|
+
const toggle = useCallback(() => setIsOpen(prev => !prev), []);
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<>
|
|
12
|
+
{renderButton?.({ close, isOpen, open, toggle })}
|
|
13
|
+
{children?.({ close, isOpen, open, toggle })}
|
|
14
|
+
</>
|
|
15
|
+
);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default DefaultModalButton;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Modal, Text, TouchableOpacity, View } from 'react-native';
|
|
3
|
+
import Icon from 'react-native-vector-icons/Feather';
|
|
4
|
+
import DefaultSearch from '../filters/DefaultSearch';
|
|
5
|
+
import styles from './DefaultTable.styles';
|
|
6
|
+
import useDefaultTableTheme from './useDefaultTableTheme';
|
|
7
|
+
|
|
8
|
+
const DefaultSearchModal = ({ storeName, visible = false, onClose }) => {
|
|
9
|
+
const { modalColors } = useDefaultTableTheme();
|
|
10
|
+
if (!visible) return null;
|
|
11
|
+
|
|
12
|
+
const {
|
|
13
|
+
backgroundColor,
|
|
14
|
+
borderColor,
|
|
15
|
+
closeIconColor,
|
|
16
|
+
headerTextColor,
|
|
17
|
+
overlayColor,
|
|
18
|
+
} = modalColors;
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<Modal visible transparent animationType="fade" onRequestClose={onClose}>
|
|
22
|
+
<View style={[styles.modalOverlay, { backgroundColor: overlayColor }]}>
|
|
23
|
+
<View style={[styles.modalCard, styles.searchModalCard, { borderColor, backgroundColor }]}>
|
|
24
|
+
<View style={[styles.modalHeader, { borderBottomColor: borderColor }]}>
|
|
25
|
+
<Text style={[styles.modalTitle, { color: headerTextColor }]} numberOfLines={1}>
|
|
26
|
+
{global.t?.t(storeName, 'label', 'search')}
|
|
27
|
+
</Text>
|
|
28
|
+
<TouchableOpacity
|
|
29
|
+
style={[styles.modalCloseButton, { borderColor, backgroundColor }]}
|
|
30
|
+
activeOpacity={0.82}
|
|
31
|
+
onPress={onClose}
|
|
32
|
+
>
|
|
33
|
+
<Icon name="x" size={16} color={closeIconColor} />
|
|
34
|
+
</TouchableOpacity>
|
|
35
|
+
</View>
|
|
36
|
+
<View style={styles.searchModalBody}>
|
|
37
|
+
<DefaultSearch
|
|
38
|
+
autoFocus
|
|
39
|
+
storeName={storeName}
|
|
40
|
+
onSearch={onClose}
|
|
41
|
+
/>
|
|
42
|
+
</View>
|
|
43
|
+
</View>
|
|
44
|
+
</View>
|
|
45
|
+
</Modal>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export default DefaultSearchModal;
|