@controleonline/ui-default 1.0.263 → 1.0.264

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 (29) hide show
  1. package/AGENTS.md +48 -47
  2. package/package.json +3 -6
  3. package/src/react/components/errors/DefaultErrors.js +360 -360
  4. package/src/react/components/files/DefaultFile.js +46 -46
  5. package/src/react/components/filters/CompactFilterSelector.js +22 -3
  6. package/src/react/components/filters/DefaultColumnFilter.js +15 -13
  7. package/src/react/components/filters/DefaultExternalFilters.js +44 -39
  8. package/src/react/components/filters/DefaultSearch.js +140 -103
  9. package/src/react/components/filters/DefaultSearch.styles.js +65 -70
  10. package/src/react/components/form/DefaultForm.js +200 -198
  11. package/src/react/components/help/DefaultTooltip.js +87 -87
  12. package/src/react/components/help/DefaultTooltip.styles.js +61 -61
  13. package/src/react/components/inputs/DefaultInput.js +162 -160
  14. package/src/react/components/inputs/DefaultSelect.js +203 -192
  15. package/src/react/components/map/DefaultGoogleMap.styles.js +115 -9
  16. package/src/react/components/map/DefaultGoogleMap.web.js +560 -446
  17. package/src/react/components/map/DefaultMap.native.js +73 -71
  18. package/src/react/components/map/DefaultMap.styles.js +16 -16
  19. package/src/react/components/map/DefaultMap.web.js +68 -66
  20. package/src/react/components/map/DefaultNativeMap.native.js +307 -183
  21. package/src/react/components/map/DefaultNativeMap.shared.js +439 -340
  22. package/src/react/components/map/DefaultNativeMap.styles.js +156 -122
  23. package/src/react/components/table/DefaultTable.js +529 -355
  24. package/src/react/components/table/DefaultTable.styles.js +30 -39
  25. package/src/react/index.js +10 -10
  26. package/src/tests/react/components/errors/DefaultErrors.test.js +162 -162
  27. package/src/tests/react/components/files/DefaultFile.test.js +80 -80
  28. package/src/tests/react/components/inputs/DefaultSelect.test.js +93 -0
  29. package/src/tests/react/components/table/DefaultTable.test.js +334 -0
@@ -1,360 +1,360 @@
1
- import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
2
- import {Modal, Pressable, Text, TouchableOpacity, View} from 'react-native';
3
- import {useStore, useStores} from '@store';
4
- import resolveSystemErrorMessage from '@controleonline/ui-common/src/react/utils/systemErrorMessage';
5
-
6
- const AUTO_CLOSE_MS = 5000;
7
-
8
- const resolveText = value => String(value ?? '').trim();
9
-
10
- const normalizeStoreNames = (store, stores) => {
11
- const resolvedStoreNames = [
12
- ...(Array.isArray(store) ? store : store ? [store] : []),
13
- ...(Array.isArray(stores) ? stores : []),
14
- ];
15
-
16
- return resolvedStoreNames.filter(name => typeof name === 'string' && name.trim()).map(name => name.trim());
17
- };
18
-
19
- const pickThemeColor = (colors, keys, fallback) => {
20
- for (const key of keys) {
21
- const value = colors?.[key];
22
-
23
- if (typeof value === 'string' && value.trim()) {
24
- return value.trim();
25
- }
26
- }
27
-
28
- return fallback;
29
- };
30
-
31
- const DefaultErrors = ({
32
- store = null,
33
- stores = [],
34
- error = null,
35
- title = '',
36
- message = '',
37
- compact = false,
38
- align = 'center',
39
- onRetry = null,
40
- retryLabel = 'Tentar novamente',
41
- containerStyle = null,
42
- contentStyle = null,
43
- titleStyle = null,
44
- messageStyle = null,
45
- retryButtonStyle = null,
46
- retryTextStyle = null,
47
- }) => {
48
- const themeStore = useStore('theme');
49
- const themeColors = themeStore?.getters?.colors || {};
50
- const allStores = typeof useStores === 'function' ? useStores(state => state) : null;
51
- const storeNames = useMemo(() => normalizeStoreNames(store, stores), [store, stores]);
52
- const watchedStoreEntries = useMemo(() => {
53
- if (!allStores || storeNames.length === 0) {
54
- return [];
55
- }
56
-
57
- return storeNames
58
- .map(storeName => {
59
- const currentStore = allStores?.[storeName] || null;
60
- const storeError = resolveSystemErrorMessage(currentStore?.getters?.error);
61
-
62
- if (!storeError) {
63
- return null;
64
- }
65
-
66
- return {
67
- error: storeError,
68
- name: storeName,
69
- store: currentStore,
70
- };
71
- })
72
- .filter(Boolean);
73
- }, [allStores, storeNames]);
74
-
75
- const explicitTitle = resolveText(title);
76
- const explicitMessage = resolveText(message) || resolveSystemErrorMessage(error);
77
- const hasStoreError = watchedStoreEntries.length > 0;
78
- const activeStoreEntry = watchedStoreEntries[0] || null;
79
- const visibleMessage = hasStoreError ? activeStoreEntry?.error || '' : explicitMessage;
80
- const hasExplicitContent = storeNames.length === 0
81
- ? Boolean(explicitTitle || explicitMessage || typeof onRetry === 'function')
82
- : Boolean(explicitMessage || typeof onRetry === 'function');
83
- const storeDriverSignature = hasStoreError
84
- ? `store:${watchedStoreEntries.map(entry => `${entry.name}:${entry.error}`).join('|')}`
85
- : '';
86
- const explicitDriverSignature = hasExplicitContent
87
- ? `explicit:${[explicitTitle, explicitMessage, typeof onRetry === 'function' ? 'retry' : '']
88
- .map(value => resolveText(value))
89
- .filter(Boolean)
90
- .join('|')}`
91
- : '';
92
- const activeDriverSignature = storeDriverSignature || explicitDriverSignature;
93
- const [dismissedSignatures, setDismissedSignatures] = useState(() => new Set());
94
- const timerRef = useRef(null);
95
- const textAlign = align === 'left' ? 'left' : 'center';
96
- const accentColor = pickThemeColor(
97
- themeColors,
98
- ['inputErrorBorder', 'textDanger', 'modalBorder', 'primary'],
99
- '#DC2626',
100
- );
101
- const backgroundColor = pickThemeColor(
102
- themeColors,
103
- ['inputErrorBackground', 'modalBackground', 'surface', 'background'],
104
- '#FFFFFF',
105
- );
106
- const overlayColor = pickThemeColor(
107
- themeColors,
108
- ['modalOverlay', 'overlayBackground'],
109
- 'rgba(15, 23, 42, 0.55)',
110
- );
111
- const titleColor = pickThemeColor(
112
- themeColors,
113
- ['inputErrorText', 'textDanger', 'modalHeaderText', 'text'],
114
- '#B91C1C',
115
- );
116
- const messageColor = pickThemeColor(
117
- themeColors,
118
- ['modalText', 'textSecondary', 'text'],
119
- '#334155',
120
- );
121
- const closeColor = pickThemeColor(
122
- themeColors,
123
- ['modalCloseIcon', 'textDanger', 'primary'],
124
- accentColor,
125
- );
126
- const retryAccentColor = pickThemeColor(themeColors, ['primary'], accentColor);
127
-
128
- const clearStoreErrors = useCallback(() => {
129
- watchedStoreEntries.forEach(entry => {
130
- const setError = entry?.store?.actions?.setError;
131
-
132
- if (typeof setError === 'function') {
133
- setError('');
134
- }
135
- });
136
- }, [watchedStoreEntries]);
137
-
138
- const dismissPopup = useCallback(() => {
139
- if (timerRef.current) {
140
- clearTimeout(timerRef.current);
141
- timerRef.current = null;
142
- }
143
-
144
- setDismissedSignatures(previous => {
145
- const next = new Set(previous);
146
-
147
- if (storeDriverSignature) {
148
- next.add(storeDriverSignature);
149
- }
150
-
151
- if (explicitDriverSignature) {
152
- next.add(explicitDriverSignature);
153
- }
154
-
155
- return next;
156
- });
157
-
158
- clearStoreErrors();
159
- }, [clearStoreErrors, explicitDriverSignature, storeDriverSignature]);
160
-
161
- const isVisible = Boolean(activeDriverSignature) && !dismissedSignatures.has(activeDriverSignature);
162
- const hasContent = Boolean(explicitTitle || visibleMessage || typeof onRetry === 'function');
163
-
164
- useEffect(() => {
165
- if (!activeDriverSignature) {
166
- if (timerRef.current) {
167
- clearTimeout(timerRef.current);
168
- timerRef.current = null;
169
- }
170
-
171
- setDismissedSignatures(previous => (previous.size > 0 ? new Set() : previous));
172
- return undefined;
173
- }
174
-
175
- if (!isVisible) {
176
- if (timerRef.current) {
177
- clearTimeout(timerRef.current);
178
- timerRef.current = null;
179
- }
180
-
181
- return undefined;
182
- }
183
-
184
- if (timerRef.current) {
185
- clearTimeout(timerRef.current);
186
- }
187
-
188
- timerRef.current = setTimeout(() => {
189
- dismissPopup();
190
- }, AUTO_CLOSE_MS);
191
-
192
- return () => {
193
- if (timerRef.current) {
194
- clearTimeout(timerRef.current);
195
- timerRef.current = null;
196
- }
197
- };
198
- }, [activeDriverSignature, dismissPopup, isVisible]);
199
-
200
- if (!isVisible || !hasContent) {
201
- return null;
202
- }
203
-
204
- return (
205
- <Modal
206
- animationType="fade"
207
- onRequestClose={dismissPopup}
208
- transparent
209
- visible={isVisible}
210
- >
211
- <Pressable
212
- accessibilityRole="button"
213
- onPress={dismissPopup}
214
- style={[
215
- {
216
- alignItems: 'center',
217
- backgroundColor: overlayColor,
218
- flex: 1,
219
- justifyContent: 'center',
220
- padding: 18,
221
- },
222
- ]}
223
- >
224
- <View
225
- onStartShouldSetResponder={() => true}
226
- style={[
227
- {
228
- backgroundColor,
229
- borderColor: accentColor,
230
- borderRadius: 16,
231
- borderWidth: 1,
232
- maxWidth: compact ? 360 : 440,
233
- padding: compact ? 14 : 16,
234
- shadowColor: accentColor,
235
- shadowOffset: {height: 10, width: 0},
236
- shadowOpacity: 0.12,
237
- shadowRadius: 18,
238
- width: '100%',
239
- elevation: 12,
240
- },
241
- containerStyle,
242
- ]}
243
- >
244
- <View
245
- style={[
246
- {
247
- alignItems: 'flex-start',
248
- flexDirection: 'row',
249
- gap: 10,
250
- justifyContent: 'space-between',
251
- },
252
- contentStyle,
253
- ]}
254
- >
255
- <View style={{flex: 1, gap: explicitTitle ? 10 : 8}}>
256
- {explicitTitle ? (
257
- <Text
258
- style={[
259
- {
260
- color: titleColor,
261
- fontSize: compact ? 14 : 15,
262
- fontWeight: '800',
263
- textAlign,
264
- },
265
- titleStyle,
266
- ]}
267
- >
268
- {explicitTitle}
269
- </Text>
270
- ) : null}
271
-
272
- {visibleMessage ? (
273
- <Text
274
- style={[
275
- {
276
- color: messageColor,
277
- fontSize: compact ? 12 : 13,
278
- lineHeight: compact ? 18 : 19,
279
- textAlign,
280
- },
281
- messageStyle,
282
- ]}
283
- >
284
- {visibleMessage}
285
- </Text>
286
- ) : null}
287
-
288
- {typeof onRetry === 'function' ? (
289
- <TouchableOpacity
290
- accessibilityRole="button"
291
- activeOpacity={0.85}
292
- onPress={onRetry}
293
- style={[
294
- {
295
- alignItems: 'center',
296
- alignSelf: textAlign === 'left' ? 'flex-start' : 'center',
297
- borderRadius: 999,
298
- borderWidth: 1,
299
- borderColor: retryAccentColor,
300
- backgroundColor: `${retryAccentColor}14`,
301
- marginTop: 4,
302
- paddingHorizontal: 12,
303
- paddingVertical: 8,
304
- },
305
- retryButtonStyle,
306
- ]}
307
- >
308
- <Text
309
- style={[
310
- {
311
- color: retryAccentColor,
312
- fontSize: 12,
313
- fontWeight: '800',
314
- },
315
- retryTextStyle,
316
- ]}
317
- >
318
- {retryLabel}
319
- </Text>
320
- </TouchableOpacity>
321
- ) : null}
322
- </View>
323
-
324
- <TouchableOpacity
325
- accessibilityLabel="Fechar erro"
326
- accessibilityRole="button"
327
- activeOpacity={0.8}
328
- onPress={dismissPopup}
329
- testID="default-errors-close"
330
- style={[
331
- {
332
- alignItems: 'center',
333
- borderColor: accentColor,
334
- borderRadius: 999,
335
- borderWidth: 1,
336
- height: 28,
337
- justifyContent: 'center',
338
- width: 28,
339
- },
340
- ]}
341
- >
342
- <Text
343
- style={{
344
- color: closeColor,
345
- fontSize: 16,
346
- fontWeight: '800',
347
- lineHeight: 16,
348
- }}
349
- >
350
- ×
351
- </Text>
352
- </TouchableOpacity>
353
- </View>
354
- </View>
355
- </Pressable>
356
- </Modal>
357
- );
358
- };
359
-
360
- export default DefaultErrors;
1
+ import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
2
+ import {Modal, Pressable, Text, TouchableOpacity, View} from 'react-native';
3
+ import {useStore, useStores} from '@store';
4
+ import resolveSystemErrorMessage from '@controleonline/ui-common/src/react/utils/systemErrorMessage';
5
+
6
+ const AUTO_CLOSE_MS = 5000;
7
+
8
+ const resolveText = value => String(value ?? '').trim();
9
+
10
+ const normalizeStoreNames = (store, stores) => {
11
+ const resolvedStoreNames = [
12
+ ...(Array.isArray(store) ? store : store ? [store] : []),
13
+ ...(Array.isArray(stores) ? stores : []),
14
+ ];
15
+
16
+ return resolvedStoreNames.filter(name => typeof name === 'string' && name.trim()).map(name => name.trim());
17
+ };
18
+
19
+ const pickThemeColor = (colors, keys, fallback) => {
20
+ for (const key of keys) {
21
+ const value = colors?.[key];
22
+
23
+ if (typeof value === 'string' && value.trim()) {
24
+ return value.trim();
25
+ }
26
+ }
27
+
28
+ return fallback;
29
+ };
30
+
31
+ const DefaultErrors = ({
32
+ store = null,
33
+ stores = [],
34
+ error = null,
35
+ title = '',
36
+ message = '',
37
+ compact = false,
38
+ align = 'center',
39
+ onRetry = null,
40
+ retryLabel = 'Tentar novamente',
41
+ containerStyle = null,
42
+ contentStyle = null,
43
+ titleStyle = null,
44
+ messageStyle = null,
45
+ retryButtonStyle = null,
46
+ retryTextStyle = null,
47
+ }) => {
48
+ const themeStore = useStore('theme');
49
+ const themeColors = themeStore?.getters?.colors || {};
50
+ const allStores = typeof useStores === 'function' ? useStores(state => state) : null;
51
+ const storeNames = useMemo(() => normalizeStoreNames(store, stores), [store, stores]);
52
+ const watchedStoreEntries = useMemo(() => {
53
+ if (!allStores || storeNames.length === 0) {
54
+ return [];
55
+ }
56
+
57
+ return storeNames
58
+ .map(storeName => {
59
+ const currentStore = allStores?.[storeName] || null;
60
+ const storeError = resolveSystemErrorMessage(currentStore?.getters?.error);
61
+
62
+ if (!storeError) {
63
+ return null;
64
+ }
65
+
66
+ return {
67
+ error: storeError,
68
+ name: storeName,
69
+ store: currentStore,
70
+ };
71
+ })
72
+ .filter(Boolean);
73
+ }, [allStores, storeNames]);
74
+
75
+ const explicitTitle = resolveText(title);
76
+ const explicitMessage = resolveText(message) || resolveSystemErrorMessage(error);
77
+ const hasStoreError = watchedStoreEntries.length > 0;
78
+ const activeStoreEntry = watchedStoreEntries[0] || null;
79
+ const visibleMessage = hasStoreError ? activeStoreEntry?.error || '' : explicitMessage;
80
+ const hasExplicitContent = storeNames.length === 0
81
+ ? Boolean(explicitTitle || explicitMessage || typeof onRetry === 'function')
82
+ : Boolean(explicitMessage || typeof onRetry === 'function');
83
+ const storeDriverSignature = hasStoreError
84
+ ? `store:${watchedStoreEntries.map(entry => `${entry.name}:${entry.error}`).join('|')}`
85
+ : '';
86
+ const explicitDriverSignature = hasExplicitContent
87
+ ? `explicit:${[explicitTitle, explicitMessage, typeof onRetry === 'function' ? 'retry' : '']
88
+ .map(value => resolveText(value))
89
+ .filter(Boolean)
90
+ .join('|')}`
91
+ : '';
92
+ const activeDriverSignature = storeDriverSignature || explicitDriverSignature;
93
+ const [dismissedSignatures, setDismissedSignatures] = useState(() => new Set());
94
+ const timerRef = useRef(null);
95
+ const textAlign = align === 'left' ? 'left' : 'center';
96
+ const accentColor = pickThemeColor(
97
+ themeColors,
98
+ ['inputErrorBorder', 'textDanger', 'modalBorder', 'primary'],
99
+ '#DC2626',
100
+ );
101
+ const backgroundColor = pickThemeColor(
102
+ themeColors,
103
+ ['inputErrorBackground', 'modalBackground', 'surface', 'background'],
104
+ '#FFFFFF',
105
+ );
106
+ const overlayColor = pickThemeColor(
107
+ themeColors,
108
+ ['modalOverlay', 'overlayBackground'],
109
+ 'rgba(15, 23, 42, 0.55)',
110
+ );
111
+ const titleColor = pickThemeColor(
112
+ themeColors,
113
+ ['inputErrorText', 'textDanger', 'modalHeaderText', 'text'],
114
+ '#B91C1C',
115
+ );
116
+ const messageColor = pickThemeColor(
117
+ themeColors,
118
+ ['modalText', 'textSecondary', 'text'],
119
+ '#334155',
120
+ );
121
+ const closeColor = pickThemeColor(
122
+ themeColors,
123
+ ['modalCloseIcon', 'textDanger', 'primary'],
124
+ accentColor,
125
+ );
126
+ const retryAccentColor = pickThemeColor(themeColors, ['primary'], accentColor);
127
+
128
+ const clearStoreErrors = useCallback(() => {
129
+ watchedStoreEntries.forEach(entry => {
130
+ const setError = entry?.store?.actions?.setError;
131
+
132
+ if (typeof setError === 'function') {
133
+ setError('');
134
+ }
135
+ });
136
+ }, [watchedStoreEntries]);
137
+
138
+ const dismissPopup = useCallback(() => {
139
+ if (timerRef.current) {
140
+ clearTimeout(timerRef.current);
141
+ timerRef.current = null;
142
+ }
143
+
144
+ setDismissedSignatures(previous => {
145
+ const next = new Set(previous);
146
+
147
+ if (storeDriverSignature) {
148
+ next.add(storeDriverSignature);
149
+ }
150
+
151
+ if (explicitDriverSignature) {
152
+ next.add(explicitDriverSignature);
153
+ }
154
+
155
+ return next;
156
+ });
157
+
158
+ clearStoreErrors();
159
+ }, [clearStoreErrors, explicitDriverSignature, storeDriverSignature]);
160
+
161
+ const isVisible = Boolean(activeDriverSignature) && !dismissedSignatures.has(activeDriverSignature);
162
+ const hasContent = Boolean(explicitTitle || visibleMessage || typeof onRetry === 'function');
163
+
164
+ useEffect(() => {
165
+ if (!activeDriverSignature) {
166
+ if (timerRef.current) {
167
+ clearTimeout(timerRef.current);
168
+ timerRef.current = null;
169
+ }
170
+
171
+ setDismissedSignatures(previous => (previous.size > 0 ? new Set() : previous));
172
+ return undefined;
173
+ }
174
+
175
+ if (!isVisible) {
176
+ if (timerRef.current) {
177
+ clearTimeout(timerRef.current);
178
+ timerRef.current = null;
179
+ }
180
+
181
+ return undefined;
182
+ }
183
+
184
+ if (timerRef.current) {
185
+ clearTimeout(timerRef.current);
186
+ }
187
+
188
+ timerRef.current = setTimeout(() => {
189
+ dismissPopup();
190
+ }, AUTO_CLOSE_MS);
191
+
192
+ return () => {
193
+ if (timerRef.current) {
194
+ clearTimeout(timerRef.current);
195
+ timerRef.current = null;
196
+ }
197
+ };
198
+ }, [activeDriverSignature, dismissPopup, isVisible]);
199
+
200
+ if (!isVisible || !hasContent) {
201
+ return null;
202
+ }
203
+
204
+ return (
205
+ <Modal
206
+ animationType="fade"
207
+ onRequestClose={dismissPopup}
208
+ transparent
209
+ visible={isVisible}
210
+ >
211
+ <Pressable
212
+ accessibilityRole="button"
213
+ onPress={dismissPopup}
214
+ style={[
215
+ {
216
+ alignItems: 'center',
217
+ backgroundColor: overlayColor,
218
+ flex: 1,
219
+ justifyContent: 'center',
220
+ padding: 18,
221
+ },
222
+ ]}
223
+ >
224
+ <View
225
+ onStartShouldSetResponder={() => true}
226
+ style={[
227
+ {
228
+ backgroundColor,
229
+ borderColor: accentColor,
230
+ borderRadius: 16,
231
+ borderWidth: 1,
232
+ maxWidth: compact ? 360 : 440,
233
+ padding: compact ? 14 : 16,
234
+ shadowColor: accentColor,
235
+ shadowOffset: {height: 10, width: 0},
236
+ shadowOpacity: 0.12,
237
+ shadowRadius: 18,
238
+ width: '100%',
239
+ elevation: 12,
240
+ },
241
+ containerStyle,
242
+ ]}
243
+ >
244
+ <View
245
+ style={[
246
+ {
247
+ alignItems: 'flex-start',
248
+ flexDirection: 'row',
249
+ gap: 10,
250
+ justifyContent: 'space-between',
251
+ },
252
+ contentStyle,
253
+ ]}
254
+ >
255
+ <View style={{flex: 1, gap: explicitTitle ? 10 : 8}}>
256
+ {explicitTitle ? (
257
+ <Text
258
+ style={[
259
+ {
260
+ color: titleColor,
261
+ fontSize: compact ? 14 : 15,
262
+ fontWeight: '800',
263
+ textAlign,
264
+ },
265
+ titleStyle,
266
+ ]}
267
+ >
268
+ {explicitTitle}
269
+ </Text>
270
+ ) : null}
271
+
272
+ {visibleMessage ? (
273
+ <Text
274
+ style={[
275
+ {
276
+ color: messageColor,
277
+ fontSize: compact ? 12 : 13,
278
+ lineHeight: compact ? 18 : 19,
279
+ textAlign,
280
+ },
281
+ messageStyle,
282
+ ]}
283
+ >
284
+ {visibleMessage}
285
+ </Text>
286
+ ) : null}
287
+
288
+ {typeof onRetry === 'function' ? (
289
+ <TouchableOpacity
290
+ accessibilityRole="button"
291
+ activeOpacity={0.85}
292
+ onPress={onRetry}
293
+ style={[
294
+ {
295
+ alignItems: 'center',
296
+ alignSelf: textAlign === 'left' ? 'flex-start' : 'center',
297
+ borderRadius: 999,
298
+ borderWidth: 1,
299
+ borderColor: retryAccentColor,
300
+ backgroundColor: `${retryAccentColor}14`,
301
+ marginTop: 4,
302
+ paddingHorizontal: 12,
303
+ paddingVertical: 8,
304
+ },
305
+ retryButtonStyle,
306
+ ]}
307
+ >
308
+ <Text
309
+ style={[
310
+ {
311
+ color: retryAccentColor,
312
+ fontSize: 12,
313
+ fontWeight: '800',
314
+ },
315
+ retryTextStyle,
316
+ ]}
317
+ >
318
+ {retryLabel}
319
+ </Text>
320
+ </TouchableOpacity>
321
+ ) : null}
322
+ </View>
323
+
324
+ <TouchableOpacity
325
+ accessibilityLabel="Fechar erro"
326
+ accessibilityRole="button"
327
+ activeOpacity={0.8}
328
+ onPress={dismissPopup}
329
+ testID="default-errors-close"
330
+ style={[
331
+ {
332
+ alignItems: 'center',
333
+ borderColor: accentColor,
334
+ borderRadius: 999,
335
+ borderWidth: 1,
336
+ height: 28,
337
+ justifyContent: 'center',
338
+ width: 28,
339
+ },
340
+ ]}
341
+ >
342
+ <Text
343
+ style={{
344
+ color: closeColor,
345
+ fontSize: 16,
346
+ fontWeight: '800',
347
+ lineHeight: 16,
348
+ }}
349
+ >
350
+ ×
351
+ </Text>
352
+ </TouchableOpacity>
353
+ </View>
354
+ </View>
355
+ </Pressable>
356
+ </Modal>
357
+ );
358
+ };
359
+
360
+ export default DefaultErrors;