@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,46 +1,46 @@
1
- import React, {memo, useMemo} from 'react';
2
- import {Image} from 'react-native';
3
- import {useStore} from '@store';
4
- import {resolveDefaultFileSource} from '@controleonline/ui-common/src/react/utils/fileUrl';
5
-
6
- const resolveCompanyFromStore = peopleGetters => {
7
- if (peopleGetters?.defaultCompany?.id) {
8
- return peopleGetters.defaultCompany;
9
- }
10
-
11
- if (peopleGetters?.currentCompany?.id) {
12
- return peopleGetters.currentCompany;
13
- }
14
-
15
- return null;
16
- };
17
-
18
- const DefaultFile = ({
19
- file,
20
- source,
21
- company,
22
- appDomain = '',
23
- headers = {},
24
- ...imageProps
25
- }) => {
26
- const peopleStore = useStore('people');
27
- const peopleGetters = peopleStore?.getters || {};
28
- const resolvedCompany = company || resolveCompanyFromStore(peopleGetters);
29
- const resolvedSource = useMemo(
30
- () =>
31
- resolveDefaultFileSource(source ?? file, {
32
- company: resolvedCompany,
33
- appDomain,
34
- headers,
35
- }),
36
- [appDomain, company, file, headers, resolvedCompany, source],
37
- );
38
-
39
- if (!resolvedSource) {
40
- return null;
41
- }
42
-
43
- return <Image {...imageProps} source={resolvedSource} />;
44
- };
45
-
46
- export default memo(DefaultFile);
1
+ import React, {memo, useMemo} from 'react';
2
+ import {Image} from 'react-native';
3
+ import {useStore} from '@store';
4
+ import {resolveDefaultFileSource} from '@controleonline/ui-common/src/react/utils/fileUrl';
5
+
6
+ const resolveCompanyFromStore = peopleGetters => {
7
+ if (peopleGetters?.defaultCompany?.id) {
8
+ return peopleGetters.defaultCompany;
9
+ }
10
+
11
+ if (peopleGetters?.currentCompany?.id) {
12
+ return peopleGetters.currentCompany;
13
+ }
14
+
15
+ return null;
16
+ };
17
+
18
+ const DefaultFile = ({
19
+ file,
20
+ source,
21
+ company,
22
+ appDomain = '',
23
+ headers = {},
24
+ ...imageProps
25
+ }) => {
26
+ const peopleStore = useStore('people');
27
+ const peopleGetters = peopleStore?.getters || {};
28
+ const resolvedCompany = company || resolveCompanyFromStore(peopleGetters);
29
+ const resolvedSource = useMemo(
30
+ () =>
31
+ resolveDefaultFileSource(source ?? file, {
32
+ company: resolvedCompany,
33
+ appDomain,
34
+ headers,
35
+ }),
36
+ [appDomain, company, file, headers, resolvedCompany, source],
37
+ );
38
+
39
+ if (!resolvedSource) {
40
+ return null;
41
+ }
42
+
43
+ return <Image {...imageProps} source={resolvedSource} />;
44
+ };
45
+
46
+ export default memo(DefaultFile);
@@ -89,6 +89,7 @@ const CompactFilterSelector = ({
89
89
  label = '',
90
90
  labelCaption = '',
91
91
  onClose = null,
92
+ onBeforeOpen = null,
92
93
  onSelect = null,
93
94
  options = [],
94
95
  selectedKey = '',
@@ -121,10 +122,28 @@ const CompactFilterSelector = ({
121
122
  }, [onClose]);
122
123
 
123
124
  const openModal = useCallback(() => {
124
- if (!disabled) {
125
- setVisible(true);
125
+ if (disabled) {
126
+ return;
126
127
  }
127
- }, [disabled]);
128
+
129
+ try {
130
+ const maybePromise = onBeforeOpen?.();
131
+ if (maybePromise && typeof maybePromise.then === 'function') {
132
+ maybePromise
133
+ .then(() => {
134
+ setVisible(true);
135
+ })
136
+ .catch(() => {
137
+ // Keep the modal closed if the lazy load fails.
138
+ });
139
+ return;
140
+ }
141
+ } catch (error) {
142
+ return;
143
+ }
144
+
145
+ setVisible(true);
146
+ }, [disabled, onBeforeOpen]);
128
147
 
129
148
  const handleSelect = useCallback(optionKey => {
130
149
  const shouldClose = onSelect?.(optionKey, {
@@ -13,11 +13,12 @@ import styles from './DefaultColumnFilter.styles';
13
13
 
14
14
  const DefaultColumnFilter = ({
15
15
  accentColor = '#2563EB',
16
- column,
17
- filters = {},
18
- getOptionsForColumn = null,
19
- onChange = null,
20
- storeName = '',
16
+ column,
17
+ filters = {},
18
+ onBeforeOpen = null,
19
+ getOptionsForColumn = null,
20
+ onChange = null,
21
+ storeName = '',
21
22
  style = null,
22
23
  }) => {
23
24
  const fieldName = getColumnKey(column);
@@ -63,14 +64,15 @@ const DefaultColumnFilter = ({
63
64
 
64
65
  return (
65
66
  <View style={[style, styles.filterCell]}>
66
- <CompactFilterSelector
67
- dense
68
- store={storeName}
69
- field={fieldName}
70
- icon="filter"
71
- accentColor={accentColor}
72
- active={Boolean(selectedKey)}
73
- label={selected?.label || options[0]?.label || ''}
67
+ <CompactFilterSelector
68
+ dense
69
+ store={storeName}
70
+ field={fieldName}
71
+ icon="filter"
72
+ onBeforeOpen={onBeforeOpen}
73
+ accentColor={accentColor}
74
+ active={Boolean(selectedKey)}
75
+ label={selected?.label || options[0]?.label || ''}
74
76
  options={options}
75
77
  selectedKey={selectedKey}
76
78
  onSelect={optionKey => {
@@ -183,11 +183,11 @@ const DefaultExternalFilters = ({
183
183
  storeName = '',
184
184
  }) => {
185
185
  const { width } = useWindowDimensions();
186
- const peopleStore = useStore('people');
187
- const themeStore = useStore('theme');
188
- const [isFiltersModalOpen, setIsFiltersModalOpen] = useState(false);
189
- const { currentCompany } = peopleStore.getters || {};
190
- const { colors: themeColors } = themeStore.getters || {};
186
+ const peopleStore = useStore('people');
187
+ const themeStore = useStore('theme');
188
+ const [isFiltersModalOpen, setIsFiltersModalOpen] = useState(false);
189
+ const { currentCompany } = peopleStore.getters || {};
190
+ const { colors: themeColors } = themeStore.getters;
191
191
  const themeTokens = useMemo(
192
192
  () => ({...themeColors, ...(currentCompany?.theme?.colors || {})}),
193
193
  [currentCompany?.theme?.colors, themeColors],
@@ -199,10 +199,15 @@ const DefaultExternalFilters = ({
199
199
  const resolvedAccentColor = accentColor || palette.primary;
200
200
  const surfaceColor = themeTokens['bg-odd-light'] || palette.background;
201
201
  const panelColor = themeTokens['bg-headers-light'] || palette.background;
202
- const borderColor = palette.border;
203
- const textColor = palette.text;
204
- const textSecondaryColor = palette.textSecondary;
205
- const onAccentColor = palette.secondary || palette.text;
202
+ const borderColor = palette.border;
203
+ const textColor = palette.text;
204
+ const textSecondaryColor = palette.textSecondary;
205
+ const buttonBackgroundColor = themeColors.buttonBackground;
206
+ const buttonTextColor = themeColors.buttonText;
207
+ const tableFilterBackgroundColor = themeColors.tableFilterBackground;
208
+ const tableFilterBorderColor = themeColors.tableFilterBorder;
209
+ const tableFilterTextColor = themeColors.tableFilterText;
210
+ const onAccentColor = palette.secondary || palette.text;
206
211
  const isCompactView = width > 0 && width <= compactBreakpoint;
207
212
  const filterColumns = useMemo(
208
213
  () => columns.filter(shouldIncludeColumn),
@@ -335,30 +340,30 @@ const DefaultExternalFilters = ({
335
340
  if (isCompactView) {
336
341
  return (
337
342
  <View style={styles.mobileWrap}>
338
- <TouchableOpacity
339
- style={[
340
- styles.mobileButton,
341
- { borderColor: borderColor, backgroundColor: surfaceColor },
342
- activeCount > 0 ? { borderColor: resolvedAccentColor, backgroundColor: withOpacity(resolvedAccentColor, 0.14) } : null,
343
- ]}
344
- activeOpacity={0.84}
345
- onPress={() => setIsFiltersModalOpen(true)}
346
- >
347
- <Icon name="filter" size={15} color={activeCount > 0 ? resolvedAccentColor : textSecondaryColor} />
348
- <Text
349
- style={[
350
- styles.mobileButtonText,
351
- { color: textColor },
352
- activeCount > 0 ? { color: resolvedAccentColor } : null,
353
- ]}
354
- >
355
- {filterTitle}
356
- </Text>
357
- {activeCount > 0 ? (
358
- <View style={[styles.mobileCountBadge, { backgroundColor: resolvedAccentColor }]}>
359
- <Text style={styles.mobileCountBadgeText}>{activeCount}</Text>
360
- </View>
361
- ) : null}
343
+ <TouchableOpacity
344
+ style={[
345
+ styles.mobileButton,
346
+ { borderColor: borderColor, backgroundColor: surfaceColor },
347
+ activeCount > 0 ? { borderColor: tableFilterBorderColor, backgroundColor: tableFilterBackgroundColor } : null,
348
+ ]}
349
+ activeOpacity={0.84}
350
+ onPress={() => setIsFiltersModalOpen(true)}
351
+ >
352
+ <Icon name="filter" size={15} color={activeCount > 0 ? tableFilterTextColor : textSecondaryColor} />
353
+ <Text
354
+ style={[
355
+ styles.mobileButtonText,
356
+ { color: textColor },
357
+ activeCount > 0 ? { color: tableFilterTextColor } : null,
358
+ ]}
359
+ >
360
+ {filterTitle}
361
+ </Text>
362
+ {activeCount > 0 ? (
363
+ <View style={[styles.mobileCountBadge, { backgroundColor: tableFilterBorderColor }]}>
364
+ <Text style={styles.mobileCountBadgeText}>{activeCount}</Text>
365
+ </View>
366
+ ) : null}
362
367
  </TouchableOpacity>
363
368
 
364
369
  <Modal
@@ -402,12 +407,12 @@ const DefaultExternalFilters = ({
402
407
  </Text>
403
408
  </TouchableOpacity>
404
409
  ) : null}
405
- <TouchableOpacity
406
- style={[styles.modalPrimaryButton, { backgroundColor: resolvedAccentColor }]}
407
- activeOpacity={0.84}
408
- onPress={() => setIsFiltersModalOpen(false)}
409
- >
410
- <Text style={[styles.modalPrimaryButtonText, { color: onAccentColor }]}>
410
+ <TouchableOpacity
411
+ style={[styles.modalPrimaryButton, { backgroundColor: buttonBackgroundColor }]}
412
+ activeOpacity={0.84}
413
+ onPress={() => setIsFiltersModalOpen(false)}
414
+ >
415
+ <Text style={[styles.modalPrimaryButtonText, { color: buttonTextColor }]}>
411
416
  {global.t?.t(storeName, 'button', 'apply')}
412
417
  </Text>
413
418
  </TouchableOpacity>
@@ -1,103 +1,140 @@
1
- import React, { useEffect, useMemo, useState } from 'react';
2
- import { TextInput, TouchableOpacity, View } from 'react-native';
3
- import Icon from 'react-native-vector-icons/Feather';
4
- import styles from './DefaultSearch.styles';
5
-
6
- const normalizeText = value => String(value || '').trim();
7
-
8
- const DefaultSearch = ({
9
- accentColor = '#2563EB',
10
- autoFocus = false,
11
- compact = false,
12
- filters = null,
13
- onChangeFilters = null,
14
- onClear = null,
15
- onSearch = null,
16
- placeholder = '',
17
- searchKey = 'search',
18
- storeName = '',
19
- style = null,
20
- value,
21
- }) => {
22
- const resolvedValue = useMemo(
23
- () => normalizeText(value ?? filters?.[searchKey]),
24
- [filters, searchKey, value],
25
- );
26
- const [draftValue, setDraftValue] = useState(resolvedValue);
27
-
28
- useEffect(() => {
29
- setDraftValue(resolvedValue);
30
- }, [resolvedValue]);
31
-
32
- const commitSearch = nextValue => {
33
- const searchValue = normalizeText(nextValue ?? draftValue);
34
-
35
- if (typeof onChangeFilters === 'function') {
36
- const nextFilters = { ...(filters || {}) };
37
- if (searchValue) nextFilters[searchKey] = searchValue;
38
- else delete nextFilters[searchKey];
39
- onChangeFilters(nextFilters);
40
- }
41
-
42
- onSearch?.(searchValue);
43
- };
44
-
45
- const clearSearch = () => {
46
- setDraftValue('');
47
-
48
- if (typeof onChangeFilters === 'function') {
49
- const nextFilters = { ...(filters || {}) };
50
- delete nextFilters[searchKey];
51
- onChangeFilters(nextFilters);
52
- }
53
-
54
- onClear?.();
55
- onSearch?.('');
56
- };
57
-
58
- const resolvedPlaceholder =
59
- placeholder ||
60
- global.t?.t(storeName, 'input', searchKey) ||
61
- global.t?.t(storeName, 'placeholder', searchKey) ||
62
- 'Buscar...';
63
-
64
- return (
65
- <View style={[styles.wrap, compact ? styles.wrapCompact : null, style]}>
66
- <Icon name="search" size={compact ? 14 : 16} color="#64748B" />
67
- <TextInput
68
- autoCapitalize="none"
69
- autoCorrect={false}
70
- autoFocus={autoFocus}
71
- placeholder={resolvedPlaceholder}
72
- placeholderTextColor="#94A3B8"
73
- returnKeyType="search"
74
- style={[styles.input, compact ? styles.inputCompact : null]}
75
- value={draftValue}
76
- onChangeText={setDraftValue}
77
- onSubmitEditing={() => commitSearch()}
78
- />
79
- {draftValue ? (
80
- <TouchableOpacity
81
- style={[styles.iconButton, compact ? styles.iconButtonCompact : null]}
82
- activeOpacity={0.82}
83
- onPress={clearSearch}
84
- >
85
- <Icon name="x" size={14} color="#64748B" />
86
- </TouchableOpacity>
87
- ) : null}
88
- <TouchableOpacity
89
- style={[
90
- styles.searchButton,
91
- compact ? styles.searchButtonCompact : null,
92
- { borderColor: accentColor },
93
- ]}
94
- activeOpacity={0.82}
95
- onPress={() => commitSearch()}
96
- >
97
- <Icon name="arrow-right" size={compact ? 13 : 15} color={accentColor} />
98
- </TouchableOpacity>
99
- </View>
100
- );
101
- };
102
-
103
- export default DefaultSearch;
1
+ import React, { useEffect, useMemo, useState } from 'react';
2
+ import { TextInput, TouchableOpacity, View } from 'react-native';
3
+ import Icon from 'react-native-vector-icons/Feather';
4
+ import { useStore } from '@store';
5
+ import styles from './DefaultSearch.styles';
6
+
7
+ const normalizeText = value => String(value || '').trim();
8
+
9
+ const DefaultSearch = ({
10
+ autoFocus = false,
11
+ compact = false,
12
+ filters = null,
13
+ onChangeFilters = null,
14
+ onClear = null,
15
+ onSearch = null,
16
+ placeholder = '',
17
+ searchKey = 'search',
18
+ storeName = '',
19
+ style = null,
20
+ value,
21
+ }) => {
22
+ const themeStore = useStore('theme');
23
+ const themeColors = themeStore.getters.colors;
24
+ const palette = useMemo(
25
+ () => ({
26
+ buttonBackgroundSecondary: themeColors.buttonBackgroundSecondary,
27
+ buttonBorder: themeColors.buttonBorder,
28
+ buttonIcon: themeColors.buttonIcon,
29
+ buttonIconSecondary: themeColors.buttonIconSecondary,
30
+ inputBackground: themeColors.inputBackground,
31
+ inputBorder: themeColors.inputBorder,
32
+ inputIcon: themeColors.inputIcon,
33
+ inputPlaceholderText: themeColors.inputPlaceholderText,
34
+ inputText: themeColors.inputText,
35
+ }),
36
+ [themeColors],
37
+ );
38
+ const resolvedValue = useMemo(
39
+ () => normalizeText(value ?? filters?.[searchKey]),
40
+ [filters, searchKey, value],
41
+ );
42
+ const [draftValue, setDraftValue] = useState(resolvedValue);
43
+
44
+ useEffect(() => {
45
+ setDraftValue(resolvedValue);
46
+ }, [resolvedValue]);
47
+
48
+ const commitSearch = nextValue => {
49
+ const searchValue = normalizeText(nextValue ?? draftValue);
50
+
51
+ if (typeof onChangeFilters === 'function') {
52
+ const nextFilters = { ...(filters || {}) };
53
+ if (searchValue) nextFilters[searchKey] = searchValue;
54
+ else delete nextFilters[searchKey];
55
+ onChangeFilters(nextFilters);
56
+ }
57
+
58
+ onSearch?.(searchValue);
59
+ };
60
+
61
+ const clearSearch = () => {
62
+ setDraftValue('');
63
+
64
+ if (typeof onChangeFilters === 'function') {
65
+ const nextFilters = { ...(filters || {}) };
66
+ delete nextFilters[searchKey];
67
+ onChangeFilters(nextFilters);
68
+ }
69
+
70
+ onClear?.();
71
+ onSearch?.('');
72
+ };
73
+
74
+ const resolvedPlaceholder =
75
+ placeholder ||
76
+ global.t?.t(storeName, 'input', searchKey) ||
77
+ global.t?.t(storeName, 'placeholder', searchKey) ||
78
+ 'Buscar...';
79
+
80
+ return (
81
+ <View
82
+ style={[
83
+ styles.wrap,
84
+ compact ? styles.wrapCompact : null,
85
+ {
86
+ backgroundColor: palette.inputBackground,
87
+ borderColor: palette.inputBorder,
88
+ },
89
+ style,
90
+ ]}
91
+ >
92
+ <Icon name="search" size={compact ? 14 : 16} color={palette.inputIcon} />
93
+ <TextInput
94
+ autoCapitalize="none"
95
+ autoCorrect={false}
96
+ autoFocus={autoFocus}
97
+ placeholder={resolvedPlaceholder}
98
+ placeholderTextColor={palette.inputPlaceholderText}
99
+ returnKeyType="search"
100
+ style={[
101
+ styles.input,
102
+ compact ? styles.inputCompact : null,
103
+ { color: palette.inputText },
104
+ ]}
105
+ value={draftValue}
106
+ onChangeText={setDraftValue}
107
+ onSubmitEditing={() => commitSearch()}
108
+ />
109
+ {draftValue ? (
110
+ <TouchableOpacity
111
+ style={[
112
+ styles.iconButton,
113
+ compact ? styles.iconButtonCompact : null,
114
+ { backgroundColor: palette.buttonBackgroundSecondary },
115
+ ]}
116
+ activeOpacity={0.82}
117
+ onPress={clearSearch}
118
+ >
119
+ <Icon name="x" size={14} color={palette.buttonIconSecondary} />
120
+ </TouchableOpacity>
121
+ ) : null}
122
+ <TouchableOpacity
123
+ style={[
124
+ styles.searchButton,
125
+ compact ? styles.searchButtonCompact : null,
126
+ {
127
+ backgroundColor: palette.buttonBackgroundSecondary,
128
+ borderColor: palette.buttonBorder,
129
+ },
130
+ ]}
131
+ activeOpacity={0.82}
132
+ onPress={() => commitSearch()}
133
+ >
134
+ <Icon name="arrow-right" size={compact ? 13 : 15} color={palette.buttonIcon} />
135
+ </TouchableOpacity>
136
+ </View>
137
+ );
138
+ };
139
+
140
+ export default DefaultSearch;
@@ -1,70 +1,65 @@
1
- import { StyleSheet } from 'react-native';
2
-
3
- const styles = StyleSheet.create({
4
- wrap: {
5
- minHeight: 40,
6
- minWidth: 180,
7
- borderWidth: 1,
8
- borderColor: '#CBD5E1',
9
- borderRadius: 12,
10
- backgroundColor: '#FFFFFF',
11
- paddingLeft: 10,
12
- paddingRight: 5,
13
- paddingVertical: 5,
14
- flexDirection: 'row',
15
- alignItems: 'center',
16
- gap: 8,
17
- },
18
- wrapCompact: {
19
- minHeight: 30,
20
- minWidth: 150,
21
- maxWidth: 240,
22
- borderRadius: 15,
23
- paddingLeft: 9,
24
- paddingRight: 3,
25
- paddingVertical: 3,
26
- gap: 6,
27
- },
28
- input: {
29
- flex: 1,
30
- minWidth: 0,
31
- padding: 0,
32
- color: '#0F172A',
33
- fontSize: 13,
34
- lineHeight: 16,
35
- fontWeight: '700',
36
- },
37
- inputCompact: {
38
- fontSize: 12,
39
- lineHeight: 14,
40
- },
41
- iconButton: {
42
- width: 28,
43
- height: 28,
44
- borderRadius: 14,
45
- alignItems: 'center',
46
- justifyContent: 'center',
47
- backgroundColor: '#F8FAFC',
48
- },
49
- iconButtonCompact: {
50
- width: 22,
51
- height: 22,
52
- borderRadius: 11,
53
- },
54
- searchButton: {
55
- width: 30,
56
- height: 30,
57
- borderRadius: 15,
58
- borderWidth: 1,
59
- alignItems: 'center',
60
- justifyContent: 'center',
61
- backgroundColor: '#FFFFFF',
62
- },
63
- searchButtonCompact: {
64
- width: 24,
65
- height: 24,
66
- borderRadius: 12,
67
- },
68
- });
69
-
70
- export default styles;
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ const styles = StyleSheet.create({
4
+ wrap: {
5
+ minHeight: 40,
6
+ minWidth: 180,
7
+ borderWidth: 1,
8
+ borderRadius: 12,
9
+ paddingLeft: 10,
10
+ paddingRight: 5,
11
+ paddingVertical: 5,
12
+ flexDirection: 'row',
13
+ alignItems: 'center',
14
+ gap: 8,
15
+ },
16
+ wrapCompact: {
17
+ minHeight: 30,
18
+ minWidth: 150,
19
+ maxWidth: 240,
20
+ borderRadius: 15,
21
+ paddingLeft: 9,
22
+ paddingRight: 3,
23
+ paddingVertical: 3,
24
+ gap: 6,
25
+ },
26
+ input: {
27
+ flex: 1,
28
+ minWidth: 0,
29
+ padding: 0,
30
+ fontSize: 13,
31
+ lineHeight: 16,
32
+ fontWeight: '700',
33
+ },
34
+ inputCompact: {
35
+ fontSize: 12,
36
+ lineHeight: 14,
37
+ },
38
+ iconButton: {
39
+ width: 28,
40
+ height: 28,
41
+ borderRadius: 14,
42
+ alignItems: 'center',
43
+ justifyContent: 'center',
44
+ },
45
+ iconButtonCompact: {
46
+ width: 22,
47
+ height: 22,
48
+ borderRadius: 11,
49
+ },
50
+ searchButton: {
51
+ width: 30,
52
+ height: 30,
53
+ borderRadius: 15,
54
+ borderWidth: 1,
55
+ alignItems: 'center',
56
+ justifyContent: 'center',
57
+ },
58
+ searchButtonCompact: {
59
+ width: 24,
60
+ height: 24,
61
+ borderRadius: 12,
62
+ },
63
+ });
64
+
65
+ export default styles;