@controleonline/ui-default 1.0.270 → 1.0.272

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.
Files changed (89) hide show
  1. package/.github/workflows/integration-source-gate.yml +68 -0
  2. package/.github/workflows/manager-worker.yml +19 -0
  3. package/AGENTS.md +46 -50
  4. package/docs/technical/Contrato-de-colunas.md +67 -0
  5. package/docs/technical/Default-Components.md +76 -0
  6. package/docs/technical/DefaultForm.md +80 -0
  7. package/docs/technical/DefaultInput-e-DefaultSelect.md +73 -0
  8. package/docs/technical/DefaultTable.md +203 -0
  9. package/docs/wiki.md +1 -0
  10. package/package.json +22 -21
  11. package/scripts/validate-wiki-pointer.cjs +13 -0
  12. package/src/react/components/address/DefaultAddress.js +435 -0
  13. package/src/react/components/address/DefaultAddress.styles.js +133 -0
  14. package/src/react/components/address/DefaultAddressMapPane.js +55 -0
  15. package/src/react/components/address/LatLonReadonlyFields.js +51 -0
  16. package/src/react/components/address/defaultAddressHelpers.js +163 -0
  17. package/src/react/components/address/defaultAddressStyles.js +136 -0
  18. package/src/react/components/address/defaultAddressUtils.js +129 -0
  19. package/src/react/components/extra-data/DefaultExtraData.js +152 -0
  20. package/src/react/components/extra-data/DefaultExtraData.styles.js +61 -0
  21. package/src/react/components/files/DefaultFile.js +231 -46
  22. package/src/react/components/files/DefaultFileColumn.js +123 -0
  23. package/src/react/components/files/DefaultFileColumn.styles.js +52 -0
  24. package/src/react/components/files/DefaultFileColumn.utils.js +104 -0
  25. package/src/react/components/filters/CompactFilterSelector.js +51 -35
  26. package/src/react/components/filters/DefaultColumnFilter.js +58 -41
  27. package/src/react/components/filters/DefaultExternalFilters.js +331 -265
  28. package/src/react/components/form/DefaultForm.js +99 -79
  29. package/src/react/components/help/DefaultTooltip.js +59 -33
  30. package/src/react/components/help/DefaultTooltip.styles.js +23 -3
  31. package/src/react/components/inputs/DefaultColorInput.js +153 -0
  32. package/src/react/components/inputs/DefaultFeatherIconPicker.js +146 -0
  33. package/src/react/components/inputs/DefaultFeatherIconPicker.styles.js +113 -0
  34. package/src/react/components/inputs/DefaultInput.js +69 -5
  35. package/src/react/components/inputs/DefaultInput.styles.js +26 -0
  36. package/src/react/components/inputs/DefaultSelect.js +134 -123
  37. package/src/react/components/inputs/defaultInputUtils.js +69 -43
  38. package/src/react/components/map/DefaultMap.native.js +73 -73
  39. package/src/react/components/map/DefaultMap.shared.js +911 -762
  40. package/src/react/components/map/DefaultMap.web.js +124 -68
  41. package/src/react/components/table/DefaultColumnMenu.js +109 -108
  42. package/src/react/components/table/DefaultDebug.js +44 -37
  43. package/src/react/components/table/DefaultSearchModal.js +9 -1
  44. package/src/react/components/table/DefaultTable.grouping.js +98 -0
  45. package/src/react/components/table/DefaultTable.js +213 -107
  46. package/src/react/components/table/DefaultTable.styles.js +367 -314
  47. package/src/react/components/table/DefaultTableBody.js +13 -8
  48. package/src/react/components/table/DefaultTableCards.js +20 -1
  49. package/src/react/components/table/DefaultTableControls.js +180 -205
  50. package/src/react/components/table/DefaultTableImportModal.js +108 -0
  51. package/src/react/components/table/DefaultTableInput.js +1 -0
  52. package/src/react/components/table/DefaultTableRowActions.js +1 -1
  53. package/src/react/components/table/DefaultTableRows.js +224 -363
  54. package/src/react/components/table/DefaultTableSearch.js +28 -5
  55. package/src/react/components/table/DefaultTableToolbar.js +92 -3
  56. package/src/react/components/table/useDefaultTablePagination.js +56 -7
  57. package/src/react/components/table/useDefaultTableStoreSync.js +164 -0
  58. package/src/react/components/upload/DefaultUpload.js +436 -0
  59. package/src/react/components/upload/DefaultUpload.styles.js +153 -0
  60. package/src/react/components/upload/DefaultUploadAttachmentsList.js +138 -0
  61. package/src/react/components/upload/DefaultUploadManagerModal.js +247 -0
  62. package/src/react/components/upload/defaultUploadHelpers.js +108 -0
  63. package/src/react/components/upload/defaultUploadLibrary.js +248 -0
  64. package/src/react/components/upload/fileUpload.js +93 -0
  65. package/src/react/hooks/usePostalCodeLookup.js +145 -0
  66. package/src/react/index.js +6 -0
  67. package/src/react/services/addressFormUtils.js +196 -0
  68. package/src/react/services/addressGeo.js +227 -0
  69. package/src/react/utils/tableVisibleColumnsPreferences.js +29 -12
  70. package/src/tests/react/components/address/defaultAddressHelpers.test.js +104 -0
  71. package/src/tests/react/components/files/DefaultFile.test.js +6 -6
  72. package/src/tests/react/components/form/DefaultForm.test.js +123 -0
  73. package/src/tests/react/components/inputs/DefaultSelect.test.js +108 -79
  74. package/src/tests/react/components/table/DefaultTable.grouping.test.js +49 -0
  75. package/src/tests/react/components/table/DefaultTable.test.js +53 -2
  76. package/src/tests/react/components/table/DefaultTableControls.filters.test.mjs +21 -0
  77. package/src/tests/react/components/table/resolveRowBackgroundColor.test.mjs +45 -0
  78. package/src/tests/react/components/table/useDefaultTableStoreSync.test.js +161 -0
  79. package/src/tests/react/components/upload/DefaultUpload.test.js +353 -0
  80. package/src/tests/react/components/upload/defaultUploadLibrary.test.js +82 -0
  81. package/src/tests/react/components/upload/peopleMediaLibraryPreview.test.mjs +57 -0
  82. package/src/tests/react/hooks/usePostalCodeLookup.test.js +40 -0
  83. package/src/tests/react/services/SMOKE-637-cep-hydrate.md +45 -0
  84. package/src/tests/react/services/addressFormUtils.test.js +176 -0
  85. package/src/tests/react/services/addressGeoLookup.async.test.js +104 -0
  86. package/src/tests/react/services/addressGeoLookup.test.js +105 -0
  87. package/src/tests/react/services/smoke-637/form-cep-12941040.png +0 -0
  88. package/src/tests/react/services/smoke-637/index.html +132 -0
  89. package/src/tests/react/utils/tableVisibleColumnsPreferences.test.js +84 -48
@@ -0,0 +1,146 @@
1
+ import React, {useEffect, useMemo, useState} from 'react';
2
+ import {
3
+ Modal,
4
+ ScrollView,
5
+ Text,
6
+ TextInput,
7
+ TouchableOpacity,
8
+ View,
9
+ } from 'react-native';
10
+ import Icon from 'react-native-vector-icons/Feather';
11
+ import FeatherGlyphMap from 'react-native-vector-icons/glyphmaps/Feather.json';
12
+ import styles from './DefaultFeatherIconPicker.styles';
13
+
14
+ export const FEATHER_ICON_OPTIONS = Object.keys(FeatherGlyphMap)
15
+ .sort((left, right) => left.localeCompare(right))
16
+ .map(name => ({
17
+ id: name,
18
+ icon: name,
19
+ label: name,
20
+ }));
21
+
22
+ export const isValidFeatherIconName = value =>
23
+ Boolean(FeatherGlyphMap[String(value || '').trim()]);
24
+
25
+ export const normalizeFeatherIconName = value => {
26
+ const icon = String(value || '').trim();
27
+ return isValidFeatherIconName(icon) ? icon : '';
28
+ };
29
+
30
+ const DefaultFeatherIconPicker = ({
31
+ accessibilityLabel = 'Selecionar icone',
32
+ modalTitle = 'Selecionar icone',
33
+ onChange,
34
+ placeholder = 'Buscar icone',
35
+ style,
36
+ value,
37
+ }) => {
38
+ const [open, setOpen] = useState(false);
39
+ const [query, setQuery] = useState('');
40
+ const selectedIcon = normalizeFeatherIconName(value);
41
+ const hasPreview = Boolean(selectedIcon);
42
+
43
+ useEffect(() => {
44
+ if (!open) {
45
+ setQuery('');
46
+ }
47
+ }, [open]);
48
+
49
+ const filteredOptions = useMemo(() => {
50
+ const normalizedQuery = query.trim().toLowerCase();
51
+ if (!normalizedQuery) return FEATHER_ICON_OPTIONS;
52
+
53
+ return FEATHER_ICON_OPTIONS.filter(option =>
54
+ option.label.toLowerCase().includes(normalizedQuery),
55
+ );
56
+ }, [query]);
57
+
58
+ const selectIcon = icon => {
59
+ onChange?.(icon);
60
+ setOpen(false);
61
+ };
62
+
63
+ return (
64
+ <>
65
+ <TouchableOpacity
66
+ accessibilityLabel={accessibilityLabel}
67
+ activeOpacity={0.82}
68
+ style={[styles.field, style]}
69
+ onPress={() => setOpen(true)}
70
+ >
71
+ <View style={styles.valueWrap}>
72
+ <Icon
73
+ name={hasPreview ? selectedIcon : 'search'}
74
+ size={17}
75
+ color={hasPreview ? '#0F172A' : '#64748B'}
76
+ />
77
+ <Text
78
+ numberOfLines={1}
79
+ style={[
80
+ styles.valueText,
81
+ !hasPreview && styles.placeholderText,
82
+ ]}
83
+ >
84
+ {selectedIcon || placeholder}
85
+ </Text>
86
+ </View>
87
+ <Icon name="chevron-down" size={14} color="#64748B" />
88
+ </TouchableOpacity>
89
+
90
+ <Modal visible={open} transparent animationType="fade" onRequestClose={() => setOpen(false)}>
91
+ <View style={styles.modalOverlay}>
92
+ <View style={styles.modalPanel}>
93
+ <View style={styles.modalHeader}>
94
+ <Text style={styles.modalTitle}>{modalTitle}</Text>
95
+ <TouchableOpacity style={styles.closeButton} onPress={() => setOpen(false)}>
96
+ <Icon name="x" size={18} color="#334155" />
97
+ </TouchableOpacity>
98
+ </View>
99
+ <TextInput
100
+ style={styles.searchInput}
101
+ value={query}
102
+ onChangeText={setQuery}
103
+ placeholder="Filtrar"
104
+ placeholderTextColor="#94A3B8"
105
+ />
106
+ <ScrollView contentContainerStyle={styles.options}>
107
+ {filteredOptions.map(option => {
108
+ const selected = option.id === selectedIcon;
109
+
110
+ return (
111
+ <TouchableOpacity
112
+ key={option.id}
113
+ style={[
114
+ styles.optionRow,
115
+ selected && styles.optionRowActive,
116
+ ]}
117
+ onPress={() => selectIcon(option.id)}
118
+ >
119
+ <View style={styles.optionGlyph}>
120
+ <Icon
121
+ name={option.icon}
122
+ size={18}
123
+ color={selected ? '#1D4ED8' : '#334155'}
124
+ />
125
+ </View>
126
+ <Text
127
+ numberOfLines={1}
128
+ style={[
129
+ styles.optionText,
130
+ selected && styles.optionTextActive,
131
+ ]}
132
+ >
133
+ {option.label}
134
+ </Text>
135
+ </TouchableOpacity>
136
+ );
137
+ })}
138
+ </ScrollView>
139
+ </View>
140
+ </View>
141
+ </Modal>
142
+ </>
143
+ );
144
+ };
145
+
146
+ export default DefaultFeatherIconPicker;
@@ -0,0 +1,113 @@
1
+ import {StyleSheet} from 'react-native';
2
+
3
+ export default StyleSheet.create({
4
+ field: {
5
+ alignItems: 'center',
6
+ backgroundColor: '#FFFFFF',
7
+ borderColor: '#CBD5E1',
8
+ borderRadius: 8,
9
+ borderWidth: 1,
10
+ flexDirection: 'row',
11
+ gap: 8,
12
+ justifyContent: 'space-between',
13
+ minHeight: 38,
14
+ paddingHorizontal: 10,
15
+ paddingVertical: 8,
16
+ },
17
+ valueWrap: {
18
+ alignItems: 'center',
19
+ flex: 1,
20
+ flexDirection: 'row',
21
+ gap: 8,
22
+ minWidth: 0,
23
+ },
24
+ valueText: {
25
+ color: '#0F172A',
26
+ flex: 1,
27
+ fontSize: 13,
28
+ fontWeight: '700',
29
+ minWidth: 0,
30
+ },
31
+ placeholderText: {
32
+ color: '#94A3B8',
33
+ },
34
+ modalOverlay: {
35
+ alignItems: 'center',
36
+ backgroundColor: 'rgba(15, 23, 42, 0.38)',
37
+ flex: 1,
38
+ justifyContent: 'center',
39
+ padding: 18,
40
+ },
41
+ modalPanel: {
42
+ backgroundColor: '#FFFFFF',
43
+ borderRadius: 8,
44
+ maxHeight: '82%',
45
+ maxWidth: 320,
46
+ padding: 14,
47
+ width: '100%',
48
+ },
49
+ modalHeader: {
50
+ alignItems: 'center',
51
+ flexDirection: 'row',
52
+ justifyContent: 'space-between',
53
+ marginBottom: 10,
54
+ },
55
+ modalTitle: {
56
+ color: '#0F172A',
57
+ fontSize: 16,
58
+ fontWeight: '800',
59
+ },
60
+ closeButton: {
61
+ alignItems: 'center',
62
+ backgroundColor: '#F1F5F9',
63
+ borderRadius: 8,
64
+ height: 34,
65
+ justifyContent: 'center',
66
+ width: 34,
67
+ },
68
+ searchInput: {
69
+ backgroundColor: '#F8FAFC',
70
+ borderColor: '#CBD5E1',
71
+ borderRadius: 8,
72
+ borderWidth: 1,
73
+ color: '#0F172A',
74
+ fontSize: 13,
75
+ fontWeight: '700',
76
+ marginBottom: 10,
77
+ minHeight: 38,
78
+ paddingHorizontal: 10,
79
+ },
80
+ options: {
81
+ gap: 6,
82
+ },
83
+ optionRow: {
84
+ alignItems: 'center',
85
+ borderColor: '#E2E8F0',
86
+ borderRadius: 8,
87
+ borderWidth: 1,
88
+ flexDirection: 'row',
89
+ gap: 10,
90
+ paddingHorizontal: 10,
91
+ paddingVertical: 9,
92
+ },
93
+ optionRowActive: {
94
+ backgroundColor: '#EFF6FF',
95
+ borderColor: '#93C5FD',
96
+ },
97
+ optionGlyph: {
98
+ alignItems: 'center',
99
+ height: 24,
100
+ justifyContent: 'center',
101
+ width: 24,
102
+ },
103
+ optionText: {
104
+ color: '#0F172A',
105
+ flex: 1,
106
+ fontSize: 13,
107
+ fontWeight: '800',
108
+ minWidth: 0,
109
+ },
110
+ optionTextActive: {
111
+ color: '#1D4ED8',
112
+ },
113
+ });
@@ -1,17 +1,23 @@
1
- import React, { useEffect, useMemo, useState } from 'react';
1
+ import React, { useEffect, useMemo, useState } from 'react';
2
2
  import { Image, Text, TextInput, TouchableOpacity, View } from 'react-native';
3
- import Icon from 'react-native-vector-icons/Feather';
3
+ import DefaultExtraData from '../extra-data/DefaultExtraData';
4
+ import DefaultFileColumn from '../files/DefaultFileColumn';
5
+ import Icon from 'react-native-vector-icons/Feather';
4
6
  import {
5
7
  buildReadPresentationStyles,
6
8
  getColumnKey,
9
+ isColorColumn,
7
10
  isDateLikeColumn,
8
11
  isEditableColumn,
12
+ isExtraDataColumn,
13
+ isFileColumn,
9
14
  isValidFeatherIcon,
10
15
  normalizeText,
11
16
  resolveCellPresentation,
12
17
  resolveCellText,
13
18
  resolveEditValue,
14
19
  } from './defaultInputUtils';
20
+ import DefaultColorInput from './DefaultColorInput';
15
21
  import DefaultDateInput from './DefaultDateInput';
16
22
  import DefaultSelect from './DefaultSelect';
17
23
  import styles from './DefaultInput.styles';
@@ -23,8 +29,9 @@ const DefaultInput = ({
23
29
  column,
24
30
  columns = [],
25
31
  containerStyle = null,
26
- displayValue,
27
- editing = false,
32
+ displayValue,
33
+ defaultColor = '',
34
+ editing = false,
28
35
  getOptionsForColumn = null,
29
36
  inputStyle = null,
30
37
  label = '',
@@ -43,7 +50,10 @@ const DefaultInput = ({
43
50
  value,
44
51
  variant = 'cell',
45
52
  }) => {
46
- const fieldName = getColumnKey(column);
53
+ const fieldName = getColumnKey(column);
54
+ const isExtraDataField = isExtraDataColumn(column) || ['extradata', 'extra_data'].includes(
55
+ normalizeText(fieldName).replace(/[^a-zA-Z0-9_]/g, '').toLowerCase(),
56
+ );
47
57
  const isForm = variant === 'form';
48
58
  const canEdit = isEditableColumn(column) && typeof onStartEditing === 'function';
49
59
  const editValue = useMemo(
@@ -98,6 +108,32 @@ const DefaultInput = ({
98
108
  );
99
109
  }
100
110
 
111
+ if (isColorColumn(column)) {
112
+ return (
113
+ <DefaultColorInput
114
+ accentColor={accentColor}
115
+ autoFocus={autoFocus}
116
+ autoSave={autoSave}
117
+ column={column}
118
+ containerStyle={containerStyle}
119
+ defaultColor={defaultColor}
120
+ editing={editing}
121
+ inputStyle={inputStyle}
122
+ label={label}
123
+ onCancelEditing={onCancelEditing}
124
+ onChangeValue={onChangeValue}
125
+ onSave={onSave}
126
+ onStartEditing={onStartEditing}
127
+ row={row}
128
+ saving={saving}
129
+ showLabel={showLabel}
130
+ storeName={storeName}
131
+ value={value}
132
+ variant={variant}
133
+ />
134
+ );
135
+ }
136
+
101
137
  if (isDateLikeColumn(column)) {
102
138
  return (
103
139
  <DefaultDateInput
@@ -143,6 +179,34 @@ const DefaultInput = ({
143
179
  };
144
180
 
145
181
  if (!editing && !isForm) {
182
+ if (isExtraDataField) {
183
+ return (
184
+ <View style={[styles.wrap, containerStyle]}>
185
+ {showLabel ? <Text style={styles.fieldLabel}>{label || column?.label || fieldName}</Text> : null}
186
+ <DefaultExtraData
187
+ column={column}
188
+ row={row}
189
+ value={value ?? row?.[fieldName]}
190
+ variant={variant}
191
+ />
192
+ </View>
193
+ );
194
+ }
195
+
196
+ if (isFileColumn(column)) {
197
+ return (
198
+ <View style={[styles.wrap, containerStyle]}>
199
+ {showLabel ? <Text style={styles.fieldLabel}>{label || column?.label || fieldName}</Text> : null}
200
+ <DefaultFileColumn
201
+ column={column}
202
+ row={row}
203
+ value={value}
204
+ variant={variant}
205
+ />
206
+ </View>
207
+ );
208
+ }
209
+
146
210
  const readIconName = isValidFeatherIcon(readPresentation.icon)
147
211
  ? readPresentation.icon
148
212
  : '';
@@ -104,6 +104,32 @@ const styles = StyleSheet.create({
104
104
  fontWeight: '600',
105
105
  backgroundColor: '#FFFFFF',
106
106
  },
107
+ colorInput: {
108
+ fontFamily: 'monospace',
109
+ textTransform: 'uppercase',
110
+ },
111
+ invalidColorInput: {
112
+ borderColor: '#DC2626',
113
+ },
114
+ colorPreview: {
115
+ width: 18,
116
+ height: 18,
117
+ flexShrink: 0,
118
+ borderWidth: 1,
119
+ borderColor: '#CBD5E1',
120
+ borderRadius: 5,
121
+ },
122
+ colorDefaultButton: {
123
+ width: 28,
124
+ height: 28,
125
+ flexShrink: 0,
126
+ alignItems: 'center',
127
+ justifyContent: 'center',
128
+ borderWidth: 1,
129
+ borderColor: '#CBD5E1',
130
+ borderRadius: 14,
131
+ backgroundColor: '#FFFFFF',
132
+ },
107
133
  formInput: {
108
134
  height: 34,
109
135
  borderColor: '#CBD5E1',