@controleonline/ui-default 1.0.276 → 1.0.278

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 (37) hide show
  1. package/docs/compact-order-history-1047.md +25 -0
  2. package/package.json +1 -1
  3. package/src/react/components/filters/CompactFilterSelector.js +194 -185
  4. package/src/react/components/filters/DefaultColumnFilter.js +8 -6
  5. package/src/react/components/filters/DefaultCompactFilterPicker.js +35 -0
  6. package/src/react/components/table/DefaultColumnMenu.js +36 -2
  7. package/src/react/components/table/DefaultCompactDialog.js +36 -0
  8. package/src/react/components/table/DefaultDebug.js +199 -197
  9. package/src/react/components/table/DefaultFiltersModal.js +44 -12
  10. package/src/react/components/table/DefaultTable.js +29 -29
  11. package/src/react/components/table/DefaultTableCards.js +18 -7
  12. package/src/react/components/table/DefaultTableCompact.helpers.js +26 -0
  13. package/src/react/components/table/DefaultTableCompact.styles.js +28 -0
  14. package/src/react/components/table/DefaultTableCompactToolbar.js +112 -0
  15. package/src/react/components/table/DefaultTableInput.js +30 -11
  16. package/src/react/components/table/DefaultTablePaginationBar.js +38 -0
  17. package/src/react/components/table/DefaultTableRows.js +17 -9
  18. package/src/react/components/table/DefaultTableToolbar.js +7 -0
  19. package/src/react/components/table/DefaultTableView.js +5 -2
  20. package/src/react/components/table/useDefaultTableCreateForm.js +29 -0
  21. package/src/react/components/table/useDefaultTablePagination.js +15 -1
  22. package/src/react/components/table/useDefaultTableRowInteraction.js +19 -0
  23. package/src/react/components/table/useDefaultTableStoreSync.js +30 -21
  24. package/src/react/components/table/useDefaultTableTheme.js +44 -41
  25. package/src/tests/react/components/table/DefaultTable.group1.test.js +441 -0
  26. package/src/tests/react/components/table/DefaultTable.group2.test.js +453 -0
  27. package/src/tests/react/components/table/DefaultTable.group3.test.js +289 -0
  28. package/src/tests/react/components/table/DefaultTable.test.js +1 -1381
  29. package/src/tests/react/components/table/DefaultTableToolbar.waiter.test.js +1 -0
  30. package/src/tests/react/components/table/compactDialogs.test.js +53 -0
  31. package/src/tests/react/components/table/compactFilters.test.js +47 -0
  32. package/src/tests/react/components/table/compactPagination.test.js +66 -0
  33. package/src/tests/react/components/table/compactTheme.test.js +34 -0
  34. package/src/tests/react/components/table/compactToolbar.test.js +41 -0
  35. package/src/tests/react/components/table/defaultTableStoreHarness.cjs +35 -0
  36. package/src/tests/react/components/table/defaultTableTestSetup.cjs +207 -0
  37. package/src/tests/react/components/table/useDefaultTableStoreSync.test.js +76 -3
@@ -12,8 +12,10 @@ import {
12
12
  sanitizeVisibleColumnsPreference,
13
13
  } from '../../utils/tableVisibleColumnsPreferences';
14
14
  import styles from './DefaultTable.styles';
15
+ import {getCompactColumnLabel} from './DefaultTableCompact.helpers';
15
16
  import { shouldIncludeColumn } from './DefaultTable.utils';
16
17
  import useDefaultTableTheme from './useDefaultTableTheme';
18
+ import DefaultCompactDialog from './DefaultCompactDialog';
17
19
 
18
20
  const DefaultColumnMenu = ({ storeName, visible = false, onClose }) => {
19
21
  const store = useStore(storeName);
@@ -41,15 +43,43 @@ const DefaultColumnMenu = ({ storeName, visible = false, onClose }) => {
41
43
  textColor,
42
44
  } = modalColors;
43
45
 
46
+ const compact = configs.appearance === 'compact';
47
+ const items = availableColumns.map(column => {
48
+ const fieldName = getColumnKey(column);
49
+ const label = getCompactColumnLabel(column, formatStoreColumnLabel({columns, fieldName, fallbackLabel: column.label || fieldName, storeName}));
50
+ const checked = visibleColumns[fieldName] !== false;
51
+ const locked = isRequiredVisibleColumn(column) || (checked && !canHideVisibleColumn({columns, fieldName, visibleColumns}));
52
+ const toggle = () => {
53
+ const next = sanitizeVisibleColumnsPreference({columns, visibleColumns: {...visibleColumns, [fieldName]: !checked}});
54
+ persistVisibleColumnsPreference(tablePreferenceScope, next);
55
+ if (store.actions?.setVisibleColumns) store.actions.setVisibleColumns(next);
56
+ else if (store.getters) store.getters.visibleColumns = next;
57
+ };
58
+ return <TouchableOpacity key={fieldName} accessibilityRole="checkbox" accessibilityLabel={label}
59
+ accessibilityState={{checked, disabled: locked && checked}} disabled={locked && checked} onPress={toggle}
60
+ style={{minHeight: 48, flexDirection: 'row', alignItems: 'center', gap: 12, paddingHorizontal: 10, borderRadius: 8, backgroundColor: checked ? themeColors.chipBackground : 'transparent'}}>
61
+ <Icon name={checked ? 'check-square' : 'square'} size={19} color={checked ? resolvedCheckboxSelectedMarkColor : resolvedCheckboxBorderColor} />
62
+ <Text style={{flex: 1, fontSize: 14, color: textColor}}>{label}</Text>
63
+ {locked && checked ? <Text style={{fontSize: 12, color: themeColors.textSecondary}}>Obrigatória</Text> : null}
64
+ </TouchableOpacity>;
65
+ });
66
+ if (compact) return <DefaultCompactDialog visible title="Colunas visíveis" description="Escolha as informações da tabela." onClose={onClose}
67
+ width={400} bodyHeight={items.length * 60 + 40} footer={<TouchableOpacity accessibilityRole="button" accessibilityLabel="Concluir seleção de colunas" onPress={onClose}
68
+ style={{minHeight: 44, justifyContent: 'center', paddingHorizontal: 18, borderRadius: 9, backgroundColor: themeColors.buttonBackground}}><Text style={{color: themeColors.buttonText, fontSize: 14, fontWeight: '600'}}>Concluir</Text></TouchableOpacity>}>
69
+ {items.length ? items : <Text style={{color: textColor}}>Nenhuma coluna disponível.</Text>}
70
+ </DefaultCompactDialog>;
71
+
44
72
  return (
45
73
  <Modal visible transparent animationType="fade" onRequestClose={onClose}>
46
74
  <View style={[styles.modalOverlay, { backgroundColor: overlayColor }]}>
47
75
  <View style={[styles.modalCard, styles.columnMenuModalCard, { borderColor, backgroundColor }]}>
48
76
  <View style={[styles.modalHeader, { borderBottomColor: borderColor }]}>
49
77
  <Text style={[styles.modalTitle, { color: headerTextColor }]} numberOfLines={1}>
50
- {global.t?.t(storeName, 'label', 'columns')}
78
+ {configs.appearance === 'compact' ? 'Colunas visíveis' : global.t?.t(storeName, 'label', 'columns')}
51
79
  </Text>
52
80
  <TouchableOpacity
81
+ accessibilityRole="button"
82
+ accessibilityLabel="Fechar seleção de colunas"
53
83
  style={[styles.modalCloseButton, { borderColor, backgroundColor }]}
54
84
  activeOpacity={0.82}
55
85
  onPress={onClose}
@@ -60,12 +90,13 @@ const DefaultColumnMenu = ({ storeName, visible = false, onClose }) => {
60
90
  <ScrollView style={styles.columnMenuModalBody} contentContainerStyle={styles.columnMenuModalList}>
61
91
  {availableColumns.map(column => {
62
92
  const fieldName = getColumnKey(column);
63
- const label = formatStoreColumnLabel({
93
+ const defaultLabel = formatStoreColumnLabel({
64
94
  columns,
65
95
  fieldName,
66
96
  fallbackLabel: column?.label || fieldName,
67
97
  storeName,
68
98
  });
99
+ const label = configs.appearance === 'compact' ? getCompactColumnLabel(column, defaultLabel) : defaultLabel;
69
100
  const checked = visibleColumns[fieldName] !== false;
70
101
  const required = isRequiredVisibleColumn(column);
71
102
  const locked =
@@ -101,6 +132,9 @@ const DefaultColumnMenu = ({ storeName, visible = false, onClose }) => {
101
132
  return (
102
133
  <TouchableOpacity
103
134
  key={fieldName}
135
+ accessibilityRole="checkbox"
136
+ accessibilityLabel={label}
137
+ accessibilityState={{checked, disabled: locked && checked}}
104
138
  style={styles.columnMenuItem}
105
139
  activeOpacity={locked ? 1 : 0.82}
106
140
  disabled={locked && checked}
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+ import {Modal, ScrollView, StyleSheet, Text, TouchableOpacity, View, useWindowDimensions} from 'react-native';
3
+ import Icon from 'react-native-vector-icons/Feather';
4
+ import useDefaultTableTheme from './useDefaultTableTheme';
5
+
6
+ // Explicit scroll height prevents RN Web's modal body from collapsing with only maxHeight.
7
+ export default function DefaultCompactDialog({visible, title, description, onClose, children, footer, bodyHeight = 400, width = 480}) {
8
+ const {height} = useWindowDimensions();
9
+ const {themeColors: c} = useDefaultTableTheme();
10
+ const scrollHeight = Math.max(80, Math.min(bodyHeight, height - (footer ? 220 : 160)));
11
+ return <Modal visible={visible} transparent animationType="fade" onRequestClose={onClose}>
12
+ <View style={[s.backdrop, {backgroundColor: c.modalOverlay}]}>
13
+ <View accessibilityViewIsModal style={[s.dialog, {maxWidth: width, backgroundColor: c.modalBackground, borderColor: c.modalBorder}]}>
14
+ <View style={[s.header, {borderBottomColor: c.border}]}>
15
+ <View style={{flex: 1, gap: 5}}><Text accessibilityRole="header" style={[s.title, {color: c.textPrimary}]}>{title}</Text>
16
+ {description ? <Text style={[s.description, {color: c.textSecondary}]}>{description}</Text> : null}</View>
17
+ <TouchableOpacity accessibilityRole="button" accessibilityLabel={`Fechar ${title.toLowerCase()}`} onPress={onClose} style={s.close}>
18
+ <Icon name="x" size={20} color={c.textSecondary} />
19
+ </TouchableOpacity>
20
+ </View>
21
+ <ScrollView keyboardShouldPersistTaps="handled" style={{height: scrollHeight, flexGrow: 0, flexShrink: 1}} contentContainerStyle={s.content}>{children}</ScrollView>
22
+ {footer ? <View style={[s.footer, {borderTopColor: c.border, backgroundColor: c.tableFooterBackground}]}>{footer}</View> : null}
23
+ </View>
24
+ </View>
25
+ </Modal>;
26
+ }
27
+
28
+ const s = StyleSheet.create({
29
+ backdrop: {flex: 1, justifyContent: 'center', alignItems: 'center', padding: 16},
30
+ dialog: {width: '100%', borderWidth: 1, borderRadius: 16, overflow: 'hidden'},
31
+ header: {paddingLeft: 20, paddingRight: 10, paddingVertical: 14, flexDirection: 'row', alignItems: 'center', gap: 8, borderBottomWidth: 1},
32
+ title: {fontSize: 18, fontWeight: '600'}, description: {fontSize: 13, lineHeight: 19},
33
+ close: {width: 44, height: 44, alignItems: 'center', justifyContent: 'center'},
34
+ content: {padding: 20, gap: 12},
35
+ footer: {paddingHorizontal: 20, paddingVertical: 12, flexDirection: 'row', justifyContent: 'flex-end', alignItems: 'center', gap: 10, borderTopWidth: 1},
36
+ });
@@ -1,182 +1,184 @@
1
- import React, { useCallback, useMemo, useState } 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 { useMessage } from '@controleonline/ui-common/src/react/components/MessageService';
6
- import { normalizeText } from '../inputs/defaultInputUtils';
7
- import styles from './DefaultTable.styles';
8
- import useDefaultTableTheme from './useDefaultTableTheme';
9
-
10
- const isObject = value =>
11
- value !== null && typeof value === 'object' && !Array.isArray(value);
12
-
13
- const formatDebugValue = value => {
14
- if (value === undefined) return '';
15
- if (typeof value === 'string') return value;
16
-
17
- try {
18
- return JSON.stringify(value, null, 2);
19
- } catch (error) {
20
- return normalizeText(value);
21
- }
22
- };
23
-
24
- const copyTextToClipboard = async text => {
25
- const normalizedText = normalizeText(text);
26
- if (!normalizedText) return false;
27
-
28
- if (
29
- typeof navigator !== 'undefined' &&
30
- navigator.clipboard &&
31
- typeof navigator.clipboard.writeText === 'function'
32
- ) {
33
- await navigator.clipboard.writeText(normalizedText);
34
- return true;
35
- }
36
-
37
- return false;
38
- };
39
-
40
- const DebugCopyButton = ({ borderColor, color, onPress }) => (
41
- <TouchableOpacity
42
- style={[styles.debugCopyButton, { borderColor }]}
43
- activeOpacity={0.82}
44
- onPress={onPress}
45
- >
46
- <Icon name="copy" size={13} color={color} />
47
- <Text style={[styles.debugCopyButtonText, { color }]}>Copiar</Text>
48
- </TouchableOpacity>
49
- );
50
-
51
- const DebugSection = ({ borderColor, children, copyText, onCopy, textColor, title }) => (
52
- <>
53
- <View style={styles.debugSectionHeader}>
54
- <Text style={[styles.debugSectionTitle, { color: textColor }]}>{title}</Text>
55
- <DebugCopyButton
56
- borderColor={borderColor}
57
- color={textColor}
58
- onPress={() => onCopy(copyText)}
59
- />
60
- </View>
61
- <Text selectable style={[styles.debugCodeBlock, { color: textColor, borderColor }]}>
62
- {children}
63
- </Text>
64
- </>
65
- );
66
-
67
- const DefaultDebug = ({
68
- storeName,
69
- }) => {
70
- const [isOpen, setIsOpen] = useState(false);
71
- const store = useStore(storeName);
72
- const configs = store?.getters?.configs || {};
1
+ import React, { useCallback, useMemo, useState } 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 { useMessage } from '@controleonline/ui-common/src/react/components/MessageService';
6
+ import { normalizeText } from '../inputs/defaultInputUtils';
7
+ import styles from './DefaultTable.styles';
8
+ import useDefaultTableTheme from './useDefaultTableTheme';
9
+
10
+ const isObject = value =>
11
+ value !== null && typeof value === 'object' && !Array.isArray(value);
12
+
13
+ const formatDebugValue = value => {
14
+ if (value === undefined) return '';
15
+ if (typeof value === 'string') return value;
16
+
17
+ try {
18
+ return JSON.stringify(value, null, 2);
19
+ } catch (error) {
20
+ return normalizeText(value);
21
+ }
22
+ };
23
+
24
+ const copyTextToClipboard = async text => {
25
+ const normalizedText = normalizeText(text);
26
+ if (!normalizedText) return false;
27
+
28
+ if (
29
+ typeof navigator !== 'undefined' &&
30
+ navigator.clipboard &&
31
+ typeof navigator.clipboard.writeText === 'function'
32
+ ) {
33
+ await navigator.clipboard.writeText(normalizedText);
34
+ return true;
35
+ }
36
+
37
+ return false;
38
+ };
39
+
40
+ const DebugCopyButton = ({ borderColor, color, onPress }) => (
41
+ <TouchableOpacity
42
+ style={[styles.debugCopyButton, { borderColor }]}
43
+ activeOpacity={0.82}
44
+ onPress={onPress}
45
+ >
46
+ <Icon name="copy" size={13} color={color} />
47
+ <Text style={[styles.debugCopyButtonText, { color }]}>Copiar</Text>
48
+ </TouchableOpacity>
49
+ );
50
+
51
+ const DebugSection = ({ borderColor, children, copyText, onCopy, textColor, title }) => (
52
+ <>
53
+ <View style={styles.debugSectionHeader}>
54
+ <Text style={[styles.debugSectionTitle, { color: textColor }]}>{title}</Text>
55
+ <DebugCopyButton
56
+ borderColor={borderColor}
57
+ color={textColor}
58
+ onPress={() => onCopy(copyText)}
59
+ />
60
+ </View>
61
+ <Text selectable style={[styles.debugCodeBlock, { color: textColor, borderColor }]}>
62
+ {children}
63
+ </Text>
64
+ </>
65
+ );
66
+
67
+ const DefaultDebug = ({
68
+ storeName,
69
+ }) => {
70
+ const [isOpen, setIsOpen] = useState(false);
71
+ const store = useStore(storeName);
72
+ const configs = store?.getters?.configs || {};
73
73
  const { showError, showSuccess } = useMessage() || {};
74
- const { modalColors, resolvedAccentColor, tableButtonColors } = useDefaultTableTheme();
75
-
76
- const resolvedDebug = isObject(store?.getters?.debug) ? store.getters.debug : {};
77
- const debugQuery = normalizeText(resolvedDebug?.query);
78
- const debugFilledQuery = normalizeText(
79
- resolvedDebug?.filledQuery || resolvedDebug?.interpolatedQuery,
80
- );
81
- const hasDebugQuery = debugQuery !== '';
82
- const debugParameters = isObject(resolvedDebug?.parameters)
83
- ? resolvedDebug.parameters
84
- : configs.debugFallbackParameters || null;
74
+ const { modalColors, resolvedAccentColor, tableButtonColors, themeColors } = useDefaultTableTheme();
75
+
76
+ const resolvedDebug = isObject(store?.getters?.debug) ? store.getters.debug : {};
77
+ const debugQuery = normalizeText(resolvedDebug?.query);
78
+ const debugFilledQuery = normalizeText(
79
+ resolvedDebug?.filledQuery || resolvedDebug?.interpolatedQuery,
80
+ );
81
+ const hasDebugQuery = debugQuery !== '';
82
+ const debugParameters = isObject(resolvedDebug?.parameters)
83
+ ? resolvedDebug.parameters
84
+ : configs.debugFallbackParameters || null;
85
85
  const debugParametersText = useMemo(
86
86
  () => formatDebugValue(debugParameters),
87
87
  [debugParameters],
88
88
  );
89
89
  const hasDebugParameters = debugParametersText !== '';
90
90
  const debugCopyText = useMemo(
91
- () =>
92
- [
93
- 'Query:',
94
- debugQuery,
95
- '',
96
- 'Parameters:',
97
- debugParametersText,
98
- '',
99
- 'Filled query:',
100
- debugFilledQuery,
101
- ].join('\n'),
102
- [debugFilledQuery, debugParametersText, debugQuery],
103
- );
104
-
105
- const requestCopyText = useCallback(
106
- text =>
107
- copyTextToClipboard(text)
108
- .then(copied => {
109
- if (copied) {
110
- showSuccess?.('Copiado');
111
- return;
112
- }
113
-
114
- showError?.('Nao foi possivel copiar automaticamente.');
115
- })
116
- .catch(() => {
117
- showError?.('Nao foi possivel copiar automaticamente.');
118
- }),
119
- [showError, showSuccess],
120
- );
121
-
91
+ () =>
92
+ [
93
+ 'Query:',
94
+ debugQuery,
95
+ '',
96
+ 'Parameters:',
97
+ debugParametersText,
98
+ '',
99
+ 'Filled query:',
100
+ debugFilledQuery,
101
+ ].join('\n'),
102
+ [debugFilledQuery, debugParametersText, debugQuery],
103
+ );
104
+
105
+ const requestCopyText = useCallback(
106
+ text =>
107
+ copyTextToClipboard(text)
108
+ .then(copied => {
109
+ if (copied) {
110
+ showSuccess?.('Copiado');
111
+ return;
112
+ }
113
+
114
+ showError?.('Nao foi possivel copiar automaticamente.');
115
+ })
116
+ .catch(() => {
117
+ showError?.('Nao foi possivel copiar automaticamente.');
118
+ }),
119
+ [showError, showSuccess],
120
+ );
121
+
122
122
  if (!hasDebugQuery && !hasDebugParameters && !debugFilledQuery) {
123
123
  return null;
124
124
  }
125
-
126
- const {
127
- backgroundColor,
128
- borderColor,
129
- closeIconColor,
130
- headerTextColor,
131
- overlayColor,
132
- textColor,
133
- } = modalColors;
134
- const {
135
- backgroundColor: buttonBackgroundColor,
136
- borderColor: buttonBorderColor,
137
- iconColor,
138
- pressedBackgroundColor,
139
- pressedBorderColor,
140
- pressedIconColor,
141
- textColor: buttonTextColor,
142
- } = tableButtonColors;
143
-
144
- return (
145
- <>
146
- <TouchableOpacity
147
- accessibilityLabel="Debug query"
148
- accessibilityRole="button"
149
- style={[
150
- styles.toolbarButton,
151
- { borderColor: buttonBorderColor, backgroundColor: buttonBackgroundColor },
152
- isOpen
153
- ? { backgroundColor: pressedBackgroundColor, borderColor: pressedBorderColor }
154
- : null,
155
- ]}
156
- activeOpacity={0.82}
157
- onPress={() => setIsOpen(true)}
158
- >
159
- <Icon name="code" size={14} color={buttonTextColor} />
160
- </TouchableOpacity>
161
-
162
- {isOpen ? (
163
- <Modal visible transparent animationType="fade" onRequestClose={() => setIsOpen(false)}>
164
- <View style={[styles.modalOverlay, { backgroundColor: overlayColor }]}>
165
- <View style={[styles.modalCard, styles.debugModalCard, { borderColor, backgroundColor }]}>
166
- <View style={[styles.modalHeader, { borderBottomColor: borderColor }]}>
167
- <Text style={[styles.modalTitle, { color: headerTextColor }]} numberOfLines={1}>
168
- Debug query
169
- </Text>
170
- <TouchableOpacity
171
- style={[styles.modalCloseButton, { borderColor, backgroundColor }]}
172
- activeOpacity={0.82}
173
- onPress={() => setIsOpen(false)}
174
- >
175
- <Icon name="x" size={16} color={closeIconColor} />
176
- </TouchableOpacity>
177
- </View>
178
-
179
- <ScrollView style={styles.debugModalBody} contentContainerStyle={styles.debugModalContent}>
125
+
126
+ const {
127
+ backgroundColor,
128
+ borderColor,
129
+ closeIconColor,
130
+ headerTextColor,
131
+ overlayColor,
132
+ textColor,
133
+ } = modalColors;
134
+ const {
135
+ backgroundColor: buttonBackgroundColor,
136
+ borderColor: buttonBorderColor,
137
+ iconColor,
138
+ pressedBackgroundColor,
139
+ pressedBorderColor,
140
+ pressedIconColor,
141
+ textColor: buttonTextColor,
142
+ } = tableButtonColors;
143
+
144
+ return (
145
+ <>
146
+ <TouchableOpacity
147
+ accessibilityLabel={themeColors.compact ? 'Diagnóstico da consulta' : 'Debug query'}
148
+ accessibilityRole="button"
149
+ style={[
150
+ styles.toolbarButton,
151
+ { borderColor: buttonBorderColor, backgroundColor: buttonBackgroundColor },
152
+ themeColors.compact ? {width: '100%', minHeight: 48, borderWidth: 0, backgroundColor: themeColors.inputBackground, paddingHorizontal: 12, gap: 8, justifyContent: 'flex-start'} : null,
153
+ isOpen
154
+ ? { backgroundColor: pressedBackgroundColor, borderColor: pressedBorderColor }
155
+ : null,
156
+ ]}
157
+ activeOpacity={0.82}
158
+ onPress={() => setIsOpen(true)}
159
+ >
160
+ <Icon name="code" size={16} color={themeColors.compact ? themeColors.textPrimary : buttonTextColor} />
161
+ {themeColors.compact ? <Text style={{fontSize: 14, color: themeColors.textPrimary}}>Diagnóstico da consulta</Text> : null}
162
+ </TouchableOpacity>
163
+
164
+ {isOpen ? (
165
+ <Modal visible transparent animationType="fade" onRequestClose={() => setIsOpen(false)}>
166
+ <View style={[styles.modalOverlay, { backgroundColor: overlayColor }]}>
167
+ <View style={[styles.modalCard, styles.debugModalCard, { borderColor, backgroundColor }]}>
168
+ <View style={[styles.modalHeader, { borderBottomColor: borderColor }]}>
169
+ <Text style={[styles.modalTitle, { color: headerTextColor }]} numberOfLines={1}>
170
+ Debug query
171
+ </Text>
172
+ <TouchableOpacity
173
+ style={[styles.modalCloseButton, { borderColor, backgroundColor }]}
174
+ activeOpacity={0.82}
175
+ onPress={() => setIsOpen(false)}
176
+ >
177
+ <Icon name="x" size={16} color={closeIconColor} />
178
+ </TouchableOpacity>
179
+ </View>
180
+
181
+ <ScrollView style={styles.debugModalBody} contentContainerStyle={styles.debugModalContent}>
180
182
  {hasDebugQuery ? (
181
183
  <DebugSection
182
184
  borderColor={borderColor}
@@ -188,7 +190,7 @@ const DefaultDebug = ({
188
190
  {debugQuery}
189
191
  </DebugSection>
190
192
  ) : null}
191
-
193
+
192
194
  {hasDebugParameters ? (
193
195
  <DebugSection
194
196
  borderColor={borderColor}
@@ -212,30 +214,30 @@ const DefaultDebug = ({
212
214
  {debugFilledQuery}
213
215
  </DebugSection>
214
216
  ) : null}
215
- </ScrollView>
216
-
217
- <View style={[styles.modalActions, { borderTopColor: borderColor }]}>
218
- <TouchableOpacity
219
- style={[styles.secondaryButton, { borderColor }]}
220
- activeOpacity={0.82}
221
- onPress={() => requestCopyText(debugCopyText)}
222
- >
223
- <Text style={[styles.secondaryButtonText, { color: textColor }]}>Copiar tudo</Text>
224
- </TouchableOpacity>
225
- <TouchableOpacity
226
- style={[styles.primaryButton, { backgroundColor: resolvedAccentColor }]}
227
- activeOpacity={0.82}
228
- onPress={() => setIsOpen(false)}
229
- >
230
- <Text style={styles.primaryButtonText}>Fechar</Text>
231
- </TouchableOpacity>
232
- </View>
233
- </View>
234
- </View>
235
- </Modal>
236
- ) : null}
237
- </>
238
- );
239
- };
240
-
241
- export default DefaultDebug;
217
+ </ScrollView>
218
+
219
+ <View style={[styles.modalActions, { borderTopColor: borderColor }]}>
220
+ <TouchableOpacity
221
+ style={[styles.secondaryButton, { borderColor }]}
222
+ activeOpacity={0.82}
223
+ onPress={() => requestCopyText(debugCopyText)}
224
+ >
225
+ <Text style={[styles.secondaryButtonText, { color: textColor }]}>Copiar tudo</Text>
226
+ </TouchableOpacity>
227
+ <TouchableOpacity
228
+ style={[styles.primaryButton, { backgroundColor: resolvedAccentColor }]}
229
+ activeOpacity={0.82}
230
+ onPress={() => setIsOpen(false)}
231
+ >
232
+ <Text style={styles.primaryButtonText}>Fechar</Text>
233
+ </TouchableOpacity>
234
+ </View>
235
+ </View>
236
+ </View>
237
+ </Modal>
238
+ ) : null}
239
+ </>
240
+ );
241
+ };
242
+
243
+ export default DefaultDebug;