@umituz/react-native-design-system 1.5.36 → 1.5.38

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 (62) hide show
  1. package/README.md +2 -2
  2. package/package.json +7 -5
  3. package/src/index.ts +29 -221
  4. package/src/presentation/organisms/AppHeader.tsx +3 -5
  5. package/src/presentation/tokens/commonStyles.ts +1 -1
  6. package/src/presentation/atoms/AtomicAvatar.tsx +0 -157
  7. package/src/presentation/atoms/AtomicAvatarGroup.tsx +0 -169
  8. package/src/presentation/atoms/AtomicBadge.tsx +0 -232
  9. package/src/presentation/atoms/AtomicButton.tsx +0 -236
  10. package/src/presentation/atoms/AtomicCard.tsx +0 -107
  11. package/src/presentation/atoms/AtomicChip.tsx +0 -223
  12. package/src/presentation/atoms/AtomicDatePicker.tsx +0 -347
  13. package/src/presentation/atoms/AtomicDivider.tsx +0 -114
  14. package/src/presentation/atoms/AtomicFab.tsx +0 -98
  15. package/src/presentation/atoms/AtomicFilter.tsx +0 -154
  16. package/src/presentation/atoms/AtomicFormError.tsx +0 -105
  17. package/src/presentation/atoms/AtomicIcon.tsx +0 -40
  18. package/src/presentation/atoms/AtomicImage.tsx +0 -149
  19. package/src/presentation/atoms/AtomicInput.tsx +0 -363
  20. package/src/presentation/atoms/AtomicNumberInput.tsx +0 -182
  21. package/src/presentation/atoms/AtomicPicker.tsx +0 -458
  22. package/src/presentation/atoms/AtomicProgress.tsx +0 -139
  23. package/src/presentation/atoms/AtomicSearchBar.tsx +0 -114
  24. package/src/presentation/atoms/AtomicSort.tsx +0 -145
  25. package/src/presentation/atoms/AtomicSwitch.tsx +0 -166
  26. package/src/presentation/atoms/AtomicText.tsx +0 -55
  27. package/src/presentation/atoms/AtomicTextArea.tsx +0 -313
  28. package/src/presentation/atoms/AtomicTouchable.tsx +0 -209
  29. package/src/presentation/atoms/fab/styles/fabStyles.ts +0 -69
  30. package/src/presentation/atoms/fab/types/index.ts +0 -82
  31. package/src/presentation/atoms/filter/styles/filterStyles.ts +0 -32
  32. package/src/presentation/atoms/filter/types/index.ts +0 -89
  33. package/src/presentation/atoms/index.ts +0 -366
  34. package/src/presentation/atoms/input/hooks/useInputState.ts +0 -15
  35. package/src/presentation/atoms/input/styles/inputStyles.ts +0 -66
  36. package/src/presentation/atoms/input/types/index.ts +0 -25
  37. package/src/presentation/atoms/picker/styles/pickerStyles.ts +0 -207
  38. package/src/presentation/atoms/picker/types/index.ts +0 -40
  39. package/src/presentation/atoms/touchable/styles/touchableStyles.ts +0 -62
  40. package/src/presentation/atoms/touchable/types/index.ts +0 -155
  41. package/src/presentation/hooks/useResponsive.ts +0 -180
  42. package/src/presentation/molecules/AtomicConfirmationModal.tsx +0 -243
  43. package/src/presentation/molecules/EmptyState.tsx +0 -130
  44. package/src/presentation/molecules/FormField.tsx +0 -128
  45. package/src/presentation/molecules/GridContainer.tsx +0 -124
  46. package/src/presentation/molecules/IconContainer.tsx +0 -94
  47. package/src/presentation/molecules/ListItem.tsx +0 -36
  48. package/src/presentation/molecules/ScreenHeader.tsx +0 -140
  49. package/src/presentation/molecules/SearchBar.tsx +0 -85
  50. package/src/presentation/molecules/SectionCard.tsx +0 -74
  51. package/src/presentation/molecules/SectionContainer.tsx +0 -106
  52. package/src/presentation/molecules/SectionHeader.tsx +0 -125
  53. package/src/presentation/molecules/confirmation-modal/styles/confirmationModalStyles.ts +0 -133
  54. package/src/presentation/molecules/confirmation-modal/types/index.ts +0 -105
  55. package/src/presentation/molecules/index.ts +0 -41
  56. package/src/presentation/molecules/listitem/styles/listItemStyles.ts +0 -19
  57. package/src/presentation/molecules/listitem/types/index.ts +0 -17
  58. package/src/presentation/organisms/FormContainer.tsx +0 -180
  59. package/src/presentation/organisms/ScreenLayout.tsx +0 -171
  60. package/src/presentation/organisms/index.ts +0 -25
  61. package/src/presentation/utils/platformConstants.ts +0 -124
  62. package/src/presentation/utils/responsive.ts +0 -516
@@ -1,145 +0,0 @@
1
- import React from 'react';
2
- import { ScrollView, View } from 'react-native';
3
- import type { StyleProp, ViewStyle } from 'react-native';
4
- import { useAppDesignTokens } from '@umituz/react-native-theme';
5
- import { AtomicChip } from './AtomicChip';
6
-
7
- /**
8
- * Sort option interface
9
- */
10
- export interface SortOption {
11
- id: string;
12
- label: string;
13
- icon?: string;
14
- }
15
-
16
- /**
17
- * Sort direction type
18
- */
19
- export type SortDirection = 'asc' | 'desc';
20
-
21
- /**
22
- * AtomicSort component props
23
- */
24
- export interface AtomicSortProps {
25
- options: SortOption[];
26
- selectedId: string | null;
27
- sortDirection: SortDirection;
28
- onSortChange: (optionId: string, direction: SortDirection) => void;
29
- showDirectionToggle?: boolean;
30
- variant?: 'outlined' | 'filled' | 'soft';
31
- color?: 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'info';
32
- size?: 'sm' | 'md' | 'lg';
33
- style?: StyleProp<ViewStyle>;
34
- testID?: string;
35
- }
36
-
37
- /**
38
- * AtomicSort - Horizontal Sort Chip Component
39
- *
40
- * A Material Design 3 compliant sort component using chip selection.
41
- * Supports single selection with ascending/descending direction toggle.
42
- *
43
- * @example
44
- * ```tsx
45
- * const [sortBy, setSortBy] = useState<string | null>('name');
46
- * const [sortDir, setSortDir] = useState<SortDirection>('asc');
47
- *
48
- * <AtomicSort
49
- * options={[
50
- * { id: 'name', label: 'Name', icon: 'sort-alpha' },
51
- * { id: 'date', label: 'Date', icon: 'schedule' },
52
- * { id: 'priority', label: 'Priority', icon: 'flag' },
53
- * ]}
54
- * selectedId={sortBy}
55
- * sortDirection={sortDir}
56
- * onSortChange={(id, dir) => {
57
- * setSortBy(id);
58
- * setSortDir(dir);
59
- * }}
60
- * showDirectionToggle={true}
61
- * />
62
- * ```
63
- *
64
- * Features:
65
- * - Horizontal scrollable sort chips
66
- * - Single selection (one active sort at a time)
67
- * - Direction toggle (click active chip to switch asc/desc)
68
- * - Visual arrow indicators (↑ asc, ↓ desc)
69
- * - Theme-aware colors from design tokens
70
- * - Icon support per sort option
71
- * - Fully controlled component
72
- *
73
- * Behavior:
74
- * - Click inactive chip → Selects it with ascending direction
75
- * - Click active chip → Toggles direction (asc ↔ desc)
76
- * - Visual feedback via filled variant for active sort
77
- */
78
- export const AtomicSort: React.FC<AtomicSortProps> = ({
79
- options,
80
- selectedId,
81
- sortDirection,
82
- onSortChange,
83
- showDirectionToggle = true,
84
- variant = 'outlined',
85
- color = 'primary',
86
- size = 'md',
87
- style,
88
- testID,
89
- }) => {
90
- const tokens = useAppDesignTokens();
91
-
92
- /**
93
- * Handle sort chip press
94
- * - If clicking active chip: Toggle direction
95
- * - If clicking inactive chip: Select it with 'asc' direction
96
- */
97
- const handleSortPress = (optionId: string) => {
98
- if (selectedId === optionId) {
99
- const newDirection = sortDirection === 'asc' ? 'desc' : 'asc';
100
- onSortChange(optionId, newDirection);
101
- } else {
102
- onSortChange(optionId, 'asc');
103
- }
104
- };
105
-
106
- const directionIcon = sortDirection === 'asc' ? 'arrow-upward' : 'arrow-downward';
107
-
108
- return (
109
- <ScrollView
110
- horizontal
111
- showsHorizontalScrollIndicator={false}
112
- contentContainerStyle={{
113
- paddingHorizontal: tokens.spacing.sm,
114
- gap: tokens.spacing.sm,
115
- }}
116
- style={[style]}
117
- testID={testID}
118
- >
119
- <View style={{ flexDirection: 'row', gap: tokens.spacing.sm }}>
120
- {options.map((option) => {
121
- const isSelected = selectedId === option.id;
122
-
123
- return (
124
- <AtomicChip
125
- key={option.id}
126
- variant={isSelected ? 'filled' : variant}
127
- color={color}
128
- size={size}
129
- leadingIcon={option.icon}
130
- trailingIcon={
131
- isSelected && showDirectionToggle ? directionIcon : undefined
132
- }
133
- selected={isSelected}
134
- clickable={true}
135
- onPress={() => handleSortPress(option.id)}
136
- testID={`sort-chip-${option.id}`}
137
- >
138
- {option.label}
139
- </AtomicChip>
140
- );
141
- })}
142
- </View>
143
- </ScrollView>
144
- );
145
- };
@@ -1,166 +0,0 @@
1
- /**
2
- * AtomicSwitch - Universal Switch Component
3
- *
4
- * Provides consistent switch/toggle functionality with theme integration
5
- * Theme: {{THEME_NAME}} ({{CATEGORY}} category)
6
- *
7
- * Atomic Design Level: ATOM
8
- * Purpose: Basic switch/toggle input
9
- *
10
- * Usage:
11
- * - Settings toggles
12
- * - Feature enable/disable
13
- * - Boolean preferences
14
- * - Form inputs
15
- */
16
-
17
- import React from 'react';
18
- import { Switch, SwitchProps, StyleSheet, ViewStyle } from 'react-native';
19
- import { useAppDesignTokens } from '@umituz/react-native-theme';
20
-
21
- // =============================================================================
22
- // TYPE DEFINITIONS
23
- // =============================================================================
24
-
25
- export interface AtomicSwitchProps extends Omit<SwitchProps, 'style'> {
26
- /** Switch value */
27
- value: boolean;
28
- /** Value change handler */
29
- onValueChange: (value: boolean) => void;
30
- /** Size variant */
31
- size?: 'sm' | 'md' | 'lg';
32
- /** Color variant */
33
- variant?: 'primary' | 'secondary' | 'success' | 'warning' | 'error';
34
- /** Disabled state */
35
- disabled?: boolean;
36
- /** Container style override */
37
- style?: ViewStyle;
38
- /** Track color override */
39
- trackColor?: { false: string; true: string };
40
- /** Thumb color override */
41
- thumbColor?: string;
42
- /** iOS specific props */
43
- ios_backgroundColor?: string;
44
- }
45
-
46
- // =============================================================================
47
- // SIZE CONFIGURATION
48
- // =============================================================================
49
-
50
- const SIZE_CONFIG = {
51
- sm: { scaleX: 0.8, scaleY: 0.8 },
52
- md: { scaleX: 1, scaleY: 1 },
53
- lg: { scaleX: 1.2, scaleY: 1.2 },
54
- } as const;
55
-
56
- // =============================================================================
57
- // COMPONENT IMPLEMENTATION
58
- // =============================================================================
59
-
60
- export const AtomicSwitch: React.FC<AtomicSwitchProps> = ({
61
- value,
62
- onValueChange,
63
- size = 'md',
64
- variant = 'primary',
65
- disabled = false,
66
- style,
67
- trackColor,
68
- thumbColor,
69
- ios_backgroundColor,
70
- ...props
71
- }) => {
72
- const tokens = useAppDesignTokens();
73
- const styles = getStyles(tokens);
74
-
75
- const sizeConfig = SIZE_CONFIG[size as 'sm' | 'md' | 'lg'];
76
- const colors = getVariantColors(tokens, variant as 'primary' | 'secondary' | 'success' | 'warning' | 'error');
77
-
78
- const defaultTrackColor = trackColor || {
79
- false: colors.trackFalse,
80
- true: colors.trackTrue,
81
- };
82
-
83
- const defaultThumbColor = thumbColor || colors.thumb;
84
- const defaultIosBackgroundColor = ios_backgroundColor || colors.trackFalse;
85
-
86
- return (
87
- <Switch
88
- value={value}
89
- onValueChange={onValueChange}
90
- disabled={disabled}
91
- trackColor={defaultTrackColor}
92
- thumbColor={defaultThumbColor}
93
- ios_backgroundColor={defaultIosBackgroundColor}
94
- style={[
95
- styles.switch,
96
- {
97
- transform: [{ scaleX: sizeConfig.scaleX }, { scaleY: sizeConfig.scaleY }],
98
- },
99
- style,
100
- ]}
101
- {...props}
102
- />
103
- );
104
- };
105
-
106
- // =============================================================================
107
- // HELPER FUNCTIONS
108
- // =============================================================================
109
-
110
- const getVariantColors = (tokens: ReturnType<typeof useAppDesignTokens>, variant: AtomicSwitchProps['variant']) => {
111
- switch (variant) {
112
- case 'primary':
113
- return {
114
- trackFalse: tokens.colors.surfaceSecondary,
115
- trackTrue: tokens.colors.primary,
116
- thumb: tokens.colors.surface,
117
- };
118
- case 'secondary':
119
- return {
120
- trackFalse: tokens.colors.surfaceSecondary,
121
- trackTrue: tokens.colors.secondary,
122
- thumb: tokens.colors.surface,
123
- };
124
- case 'success':
125
- return {
126
- trackFalse: tokens.colors.surfaceSecondary,
127
- trackTrue: tokens.colors.success,
128
- thumb: tokens.colors.surface,
129
- };
130
- case 'warning':
131
- return {
132
- trackFalse: tokens.colors.surfaceSecondary,
133
- trackTrue: tokens.colors.warning,
134
- thumb: tokens.colors.surface,
135
- };
136
- case 'error':
137
- return {
138
- trackFalse: tokens.colors.surfaceSecondary,
139
- trackTrue: tokens.colors.error,
140
- thumb: tokens.colors.surface,
141
- };
142
- default:
143
- return {
144
- trackFalse: tokens.colors.surfaceSecondary,
145
- trackTrue: tokens.colors.primary,
146
- thumb: tokens.colors.surface,
147
- };
148
- }
149
- };
150
-
151
- // =============================================================================
152
- // STYLES
153
- // =============================================================================
154
-
155
- const getStyles = (tokens: ReturnType<typeof useAppDesignTokens>) =>
156
- StyleSheet.create({
157
- switch: {
158
- // Default switch styling is handled by platform
159
- },
160
- });
161
-
162
- // =============================================================================
163
- // EXPORTS
164
- // =============================================================================
165
-
166
- export default AtomicSwitch;
@@ -1,55 +0,0 @@
1
- import React from 'react';
2
- import { Text, StyleProp, TextStyle } from 'react-native';
3
- import { useAppDesignTokens } from '@umituz/react-native-theme';
4
- import type { TextStyleVariant, ColorVariant } from '@umituz/react-native-typography';
5
- import { getTextColor } from '@umituz/react-native-typography';
6
-
7
- export interface AtomicTextProps {
8
- children: React.ReactNode;
9
- type?: TextStyleVariant;
10
- color?: ColorVariant | string;
11
- numberOfLines?: number;
12
- ellipsizeMode?: 'head' | 'middle' | 'tail' | 'clip';
13
- textAlign?: 'auto' | 'left' | 'right' | 'center' | 'justify';
14
- style?: StyleProp<TextStyle>;
15
- testID?: string;
16
- }
17
-
18
- export const AtomicText: React.FC<AtomicTextProps> = ({
19
- children,
20
- type = 'bodyMedium',
21
- color,
22
- numberOfLines,
23
- ellipsizeMode,
24
- textAlign,
25
- style,
26
- testID,
27
- }) => {
28
- const tokens = useAppDesignTokens();
29
-
30
- // Get typography style from tokens
31
- const typographyStyle = tokens.typography[type];
32
-
33
- // Get color from tokens or use custom color using utility function
34
- const resolvedColor = getTextColor(color, tokens);
35
-
36
- const textStyle: StyleProp<TextStyle> = [
37
- typographyStyle,
38
- {
39
- color: resolvedColor,
40
- ...(textAlign && { textAlign }),
41
- },
42
- style,
43
- ];
44
-
45
- return (
46
- <Text
47
- numberOfLines={numberOfLines}
48
- ellipsizeMode={ellipsizeMode}
49
- style={textStyle}
50
- testID={testID}
51
- >
52
- {children}
53
- </Text>
54
- );
55
- };
@@ -1,313 +0,0 @@
1
- /**
2
- * AtomicTextArea Component
3
- *
4
- * A multiline text input component with pure React Native implementation
5
- * for longer text entry with consistent styling.
6
- *
7
- * Features:
8
- * - Pure React Native TextInput with multiline
9
- * - Outlined/filled/flat variants
10
- * - Error, success, disabled states
11
- * - Character counter with max length
12
- * - Helper text for guidance or errors
13
- * - Configurable rows for height
14
- * - Theme-aware styling
15
- * - Full accessibility support
16
- *
17
- * Usage:
18
- * ```tsx
19
- * const [description, setDescription] = useState('');
20
- *
21
- * <AtomicTextArea
22
- * value={description}
23
- * onChangeText={setDescription}
24
- * label="Description"
25
- * placeholder="Enter description..."
26
- * maxLength={500}
27
- * showCharacterCount
28
- * rows={6}
29
- * helperText="Provide a detailed description"
30
- * />
31
- * ```
32
- */
33
-
34
- import React, { useState } from 'react';
35
- import { View, TextInput, StyleSheet, StyleProp, ViewStyle, TextStyle } from 'react-native';
36
- import { useAppDesignTokens } from '@umituz/react-native-theme';
37
- import { AtomicText } from './AtomicText';
38
-
39
- export type AtomicTextAreaVariant = 'outlined' | 'filled' | 'flat';
40
- export type AtomicTextAreaState = 'default' | 'error' | 'success' | 'disabled';
41
- export type AtomicTextAreaSize = 'sm' | 'md' | 'lg';
42
-
43
- export interface AtomicTextAreaProps {
44
- /** Textarea label */
45
- label?: string;
46
- /** Current textarea value */
47
- value?: string;
48
- /** Value change callback */
49
- onChangeText?: (text: string) => void;
50
- /** Textarea variant (outlined, filled, flat) */
51
- variant?: AtomicTextAreaVariant;
52
- /** Textarea state (default, error, success, disabled) */
53
- state?: AtomicTextAreaState;
54
- /** Textarea size (sm, md, lg) */
55
- size?: AtomicTextAreaSize;
56
- /** Placeholder text */
57
- placeholder?: string;
58
- /** Helper text below textarea */
59
- helperText?: string;
60
- /** Maximum character length */
61
- maxLength?: number;
62
- /** Show character counter */
63
- showCharacterCount?: boolean;
64
- /** Number of visible text rows */
65
- rows?: number;
66
- /** Minimum height in pixels */
67
- minHeight?: number;
68
- /** Auto-capitalize */
69
- autoCapitalize?: 'none' | 'sentences' | 'words' | 'characters';
70
- /** Auto-correct */
71
- autoCorrect?: boolean;
72
- /** Disabled state */
73
- disabled?: boolean;
74
- /** Container style */
75
- style?: StyleProp<ViewStyle>;
76
- /** Input text style */
77
- inputStyle?: StyleProp<TextStyle>;
78
- /** Test ID for E2E testing */
79
- testID?: string;
80
- /** Blur callback */
81
- onBlur?: () => void;
82
- /** Focus callback */
83
- onFocus?: () => void;
84
- }
85
-
86
- /**
87
- * AtomicTextArea - Pure React Native Multiline Text Input
88
- */
89
- export const AtomicTextArea: React.FC<AtomicTextAreaProps> = ({
90
- variant = 'outlined',
91
- state = 'default',
92
- size = 'md',
93
- label,
94
- value = '',
95
- onChangeText,
96
- placeholder,
97
- helperText,
98
- maxLength,
99
- showCharacterCount = false,
100
- rows = 4,
101
- minHeight,
102
- autoCapitalize = 'sentences',
103
- autoCorrect = true,
104
- disabled = false,
105
- style,
106
- inputStyle,
107
- testID,
108
- onBlur,
109
- onFocus,
110
- }) => {
111
- const tokens = useAppDesignTokens();
112
- const [isFocused, setIsFocused] = useState(false);
113
- const isDisabled = state === 'disabled' || disabled;
114
- const characterCount = value?.toString().length || 0;
115
- const hasError = state === 'error';
116
- const hasSuccess = state === 'success';
117
-
118
- // Size configuration
119
- const sizeConfig = {
120
- sm: {
121
- paddingVertical: tokens.spacing.xs,
122
- paddingHorizontal: tokens.spacing.sm,
123
- fontSize: tokens.typography.bodySmall.fontSize,
124
- lineHeight: 20,
125
- },
126
- md: {
127
- paddingVertical: tokens.spacing.sm,
128
- paddingHorizontal: tokens.spacing.md,
129
- fontSize: tokens.typography.bodyMedium.fontSize,
130
- lineHeight: 24,
131
- },
132
- lg: {
133
- paddingVertical: tokens.spacing.md,
134
- paddingHorizontal: tokens.spacing.lg,
135
- fontSize: tokens.typography.bodyLarge.fontSize,
136
- lineHeight: 28,
137
- },
138
- };
139
-
140
- const config = sizeConfig[size];
141
-
142
- // Calculate height based on rows
143
- const getTextAreaHeight = () => {
144
- if (minHeight) return minHeight;
145
- const paddingVertical = config.paddingVertical * 2;
146
- return (rows * config.lineHeight) + paddingVertical;
147
- };
148
-
149
- // Get variant styles
150
- const getVariantStyle = (): ViewStyle => {
151
- const baseStyle: ViewStyle = {
152
- backgroundColor: tokens.colors.surface,
153
- borderRadius: tokens.borders.radius.md,
154
- };
155
-
156
- let borderColor = tokens.colors.border;
157
- if (isFocused) borderColor = tokens.colors.primary;
158
- if (hasError) borderColor = tokens.colors.error;
159
- if (hasSuccess) borderColor = tokens.colors.success;
160
- if (isDisabled) borderColor = tokens.colors.borderDisabled;
161
-
162
- switch (variant) {
163
- case 'outlined':
164
- return {
165
- ...baseStyle,
166
- borderWidth: isFocused ? 2 : 1,
167
- borderColor,
168
- };
169
-
170
- case 'filled':
171
- return {
172
- ...baseStyle,
173
- backgroundColor: tokens.colors.surfaceSecondary,
174
- borderWidth: 0,
175
- borderBottomWidth: isFocused ? 2 : 1,
176
- borderBottomColor: borderColor,
177
- };
178
-
179
- case 'flat':
180
- return {
181
- ...baseStyle,
182
- backgroundColor: 'transparent',
183
- borderWidth: 0,
184
- borderBottomWidth: 1,
185
- borderBottomColor: borderColor,
186
- borderRadius: 0,
187
- };
188
-
189
- default:
190
- return baseStyle;
191
- }
192
- };
193
-
194
- // Get text color based on state
195
- const getTextColor = () => {
196
- if (isDisabled) return tokens.colors.textDisabled;
197
- if (hasError) return tokens.colors.error;
198
- if (hasSuccess) return tokens.colors.success;
199
- return tokens.colors.textPrimary;
200
- };
201
-
202
- const containerStyle: StyleProp<ViewStyle> = [
203
- styles.container,
204
- getVariantStyle(),
205
- {
206
- paddingVertical: config.paddingVertical,
207
- paddingHorizontal: config.paddingHorizontal,
208
- height: getTextAreaHeight(),
209
- opacity: isDisabled ? 0.5 : 1,
210
- },
211
- style,
212
- ];
213
-
214
- const textInputStyle: StyleProp<TextStyle> = [
215
- styles.input,
216
- {
217
- fontSize: config.fontSize,
218
- lineHeight: config.lineHeight,
219
- color: getTextColor(),
220
- },
221
- inputStyle,
222
- ];
223
-
224
- return (
225
- <View testID={testID}>
226
- {label && (
227
- <AtomicText
228
- type="labelMedium"
229
- color={hasError ? 'error' : hasSuccess ? 'success' : 'secondary'}
230
- style={styles.label}
231
- >
232
- {label}
233
- </AtomicText>
234
- )}
235
-
236
- <View style={containerStyle}>
237
- <TextInput
238
- value={value}
239
- onChangeText={onChangeText}
240
- placeholder={placeholder}
241
- placeholderTextColor={tokens.colors.textSecondary}
242
- maxLength={maxLength}
243
- autoCapitalize={autoCapitalize}
244
- autoCorrect={autoCorrect}
245
- editable={!isDisabled}
246
- multiline={true}
247
- numberOfLines={rows}
248
- textAlignVertical="top"
249
- style={textInputStyle}
250
- onBlur={() => {
251
- setIsFocused(false);
252
- onBlur?.();
253
- }}
254
- onFocus={() => {
255
- setIsFocused(true);
256
- onFocus?.();
257
- }}
258
- testID={testID ? `${testID}-input` : undefined}
259
- />
260
- </View>
261
-
262
- {(helperText || showCharacterCount) && (
263
- <View style={styles.helperRow}>
264
- {helperText && (
265
- <AtomicText
266
- type="bodySmall"
267
- color={hasError ? 'error' : 'secondary'}
268
- style={styles.helperText}
269
- testID={testID ? `${testID}-helper` : undefined}
270
- >
271
- {helperText}
272
- </AtomicText>
273
- )}
274
- {showCharacterCount && maxLength && (
275
- <AtomicText
276
- type="bodySmall"
277
- color="secondary"
278
- style={styles.characterCount}
279
- testID={testID ? `${testID}-count` : undefined}
280
- >
281
- {characterCount}/{maxLength}
282
- </AtomicText>
283
- )}
284
- </View>
285
- )}
286
- </View>
287
- );
288
- };
289
-
290
- const styles = StyleSheet.create({
291
- container: {
292
- justifyContent: 'flex-start',
293
- },
294
- input: {
295
- flex: 1,
296
- },
297
- label: {
298
- marginBottom: 4,
299
- },
300
- helperRow: {
301
- flexDirection: 'row',
302
- justifyContent: 'space-between',
303
- marginTop: 4,
304
- },
305
- helperText: {
306
- flex: 1,
307
- },
308
- characterCount: {
309
- marginLeft: 8,
310
- },
311
- });
312
-
313
- export type { AtomicTextAreaProps as TextAreaProps };