@umituz/react-native-design-system 1.0.0

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 (80) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +157 -0
  3. package/package.json +43 -0
  4. package/src/index.ts +345 -0
  5. package/src/presentation/atoms/AtomicAvatar.tsx +157 -0
  6. package/src/presentation/atoms/AtomicAvatarGroup.tsx +169 -0
  7. package/src/presentation/atoms/AtomicBadge.tsx +232 -0
  8. package/src/presentation/atoms/AtomicButton.tsx +124 -0
  9. package/src/presentation/atoms/AtomicCard.tsx +112 -0
  10. package/src/presentation/atoms/AtomicChip.tsx +223 -0
  11. package/src/presentation/atoms/AtomicDatePicker.tsx +347 -0
  12. package/src/presentation/atoms/AtomicDivider.tsx +114 -0
  13. package/src/presentation/atoms/AtomicFab.tsx +104 -0
  14. package/src/presentation/atoms/AtomicFilter.tsx +154 -0
  15. package/src/presentation/atoms/AtomicFormError.tsx +105 -0
  16. package/src/presentation/atoms/AtomicIcon.tsx +29 -0
  17. package/src/presentation/atoms/AtomicImage.tsx +149 -0
  18. package/src/presentation/atoms/AtomicInput.tsx +232 -0
  19. package/src/presentation/atoms/AtomicNumberInput.tsx +182 -0
  20. package/src/presentation/atoms/AtomicPicker.tsx +458 -0
  21. package/src/presentation/atoms/AtomicProgress.tsx +143 -0
  22. package/src/presentation/atoms/AtomicSearchBar.tsx +114 -0
  23. package/src/presentation/atoms/AtomicSkeleton.tsx +146 -0
  24. package/src/presentation/atoms/AtomicSort.tsx +145 -0
  25. package/src/presentation/atoms/AtomicSwitch.tsx +166 -0
  26. package/src/presentation/atoms/AtomicText.tsx +50 -0
  27. package/src/presentation/atoms/AtomicTextArea.tsx +198 -0
  28. package/src/presentation/atoms/AtomicTouchable.tsx +233 -0
  29. package/src/presentation/atoms/fab/styles/fabStyles.ts +69 -0
  30. package/src/presentation/atoms/fab/types/index.ts +88 -0
  31. package/src/presentation/atoms/filter/styles/filterStyles.ts +32 -0
  32. package/src/presentation/atoms/filter/types/index.ts +89 -0
  33. package/src/presentation/atoms/index.ts +378 -0
  34. package/src/presentation/atoms/input/hooks/useInputState.ts +15 -0
  35. package/src/presentation/atoms/input/styles/inputStyles.ts +66 -0
  36. package/src/presentation/atoms/input/types/index.ts +25 -0
  37. package/src/presentation/atoms/picker/styles/pickerStyles.ts +200 -0
  38. package/src/presentation/atoms/picker/types/index.ts +40 -0
  39. package/src/presentation/atoms/touchable/styles/touchableStyles.ts +71 -0
  40. package/src/presentation/atoms/touchable/types/index.ts +162 -0
  41. package/src/presentation/hooks/useAppDesignTokens.ts +78 -0
  42. package/src/presentation/hooks/useResponsive.ts +180 -0
  43. package/src/presentation/loading/index.ts +40 -0
  44. package/src/presentation/loading/presentation/components/LoadingSpinner.tsx +116 -0
  45. package/src/presentation/loading/presentation/components/LoadingState.tsx +200 -0
  46. package/src/presentation/loading/presentation/hooks/useLoading.ts +100 -0
  47. package/src/presentation/molecules/AtomicConfirmationModal.tsx +263 -0
  48. package/src/presentation/molecules/EmptyState.tsx +130 -0
  49. package/src/presentation/molecules/FormField.tsx +128 -0
  50. package/src/presentation/molecules/GridContainer.tsx +124 -0
  51. package/src/presentation/molecules/IconContainer.tsx +94 -0
  52. package/src/presentation/molecules/LanguageSwitcher.tsx +42 -0
  53. package/src/presentation/molecules/ListItem.tsx +36 -0
  54. package/src/presentation/molecules/ScreenHeader.tsx +140 -0
  55. package/src/presentation/molecules/SearchBar.tsx +85 -0
  56. package/src/presentation/molecules/SectionCard.tsx +74 -0
  57. package/src/presentation/molecules/SectionContainer.tsx +106 -0
  58. package/src/presentation/molecules/SectionHeader.tsx +125 -0
  59. package/src/presentation/molecules/confirmation-modal/styles/confirmationModalStyles.ts +133 -0
  60. package/src/presentation/molecules/confirmation-modal/types/index.ts +107 -0
  61. package/src/presentation/molecules/index.ts +42 -0
  62. package/src/presentation/molecules/languageswitcher/config/languageSwitcherConfig.ts +5 -0
  63. package/src/presentation/molecules/languageswitcher/hooks/useLanguageNavigation.ts +15 -0
  64. package/src/presentation/molecules/listitem/styles/listItemStyles.ts +19 -0
  65. package/src/presentation/molecules/listitem/types/index.ts +17 -0
  66. package/src/presentation/organisms/AppHeader.tsx +136 -0
  67. package/src/presentation/organisms/FormContainer.tsx +180 -0
  68. package/src/presentation/organisms/ScreenLayout.tsx +209 -0
  69. package/src/presentation/organisms/index.ts +25 -0
  70. package/src/presentation/tokens/AppDesignTokens.ts +57 -0
  71. package/src/presentation/tokens/commonStyles.ts +253 -0
  72. package/src/presentation/tokens/core/BaseTokens.ts +394 -0
  73. package/src/presentation/tokens/core/ColorPalette.ts +398 -0
  74. package/src/presentation/tokens/core/TokenFactory.ts +120 -0
  75. package/src/presentation/utils/platformConstants.ts +124 -0
  76. package/src/presentation/utils/responsive.ts +516 -0
  77. package/src/presentation/utils/variants/compound.ts +29 -0
  78. package/src/presentation/utils/variants/core.ts +39 -0
  79. package/src/presentation/utils/variants/helpers.ts +13 -0
  80. package/src/presentation/utils/variants.ts +3 -0
@@ -0,0 +1,378 @@
1
+ /**
2
+ * Atomic Components Export Index
3
+ *
4
+ * Centralized export file for all atomic design components
5
+ * Following atomic design principles with React Native implementation
6
+ *
7
+ * Generated for {{APP_NAME}} - {{CATEGORY}} category
8
+ * Theme: {{THEME_NAME}}
9
+ *
10
+ * Usage:
11
+ * ```typescript
12
+ * import { AtomicButton, AtomicText, AtomicCard } from '@domains/design-system';
13
+ *
14
+ * // Or individual imports
15
+ * import { AtomicButton } from '@domains/design-system';
16
+ * ```
17
+ */
18
+
19
+ // STEP 1: Import all components first (required for default export)
20
+ import {
21
+ AtomicButton,
22
+ type AtomicButtonProps,
23
+ } from './AtomicButton';
24
+
25
+ import {
26
+ AtomicText,
27
+ type AtomicTextProps,
28
+ } from './AtomicText';
29
+
30
+ import {
31
+ AtomicCard,
32
+ type AtomicCardProps,
33
+ type AtomicCardVariant,
34
+ type AtomicCardPadding,
35
+ } from './AtomicCard';
36
+
37
+ import {
38
+ AtomicInput,
39
+ type AtomicInputProps,
40
+ type AtomicInputVariant,
41
+ type AtomicInputState,
42
+ type AtomicInputSize,
43
+ } from './AtomicInput';
44
+
45
+ import {
46
+ AtomicIcon,
47
+ type AtomicIconProps,
48
+ type AtomicIconSize,
49
+ type AtomicIconColor,
50
+ } from './AtomicIcon';
51
+
52
+ import {
53
+ AtomicImage,
54
+ type AtomicImageProps,
55
+ } from './AtomicImage';
56
+
57
+ import {
58
+ AtomicSwitch,
59
+ type AtomicSwitchProps,
60
+ } from './AtomicSwitch';
61
+
62
+ import {
63
+ AtomicBadge,
64
+ type AtomicBadgeProps,
65
+ } from './AtomicBadge';
66
+
67
+ import {
68
+ AtomicFormError,
69
+ type AtomicFormErrorProps,
70
+ } from './AtomicFormError';
71
+
72
+ import {
73
+ AtomicAvatar,
74
+ type AtomicAvatarProps,
75
+ } from './AtomicAvatar';
76
+
77
+ import {
78
+ AtomicChip,
79
+ type AtomicChipProps,
80
+ } from './AtomicChip';
81
+
82
+ import {
83
+ AtomicDivider,
84
+ type AtomicDividerProps,
85
+ } from './AtomicDivider';
86
+
87
+ import {
88
+ AtomicSkeleton,
89
+ type AtomicSkeletonProps,
90
+ } from './AtomicSkeleton';
91
+
92
+ import {
93
+ AtomicProgress,
94
+ type AtomicProgressProps,
95
+ } from './AtomicProgress';
96
+
97
+ import {
98
+ AtomicAvatarGroup,
99
+ type AtomicAvatarGroupProps,
100
+ type AvatarData,
101
+ } from './AtomicAvatarGroup';
102
+
103
+ import {
104
+ AtomicFab,
105
+ type AtomicFabProps,
106
+ type FabSize,
107
+ type FabVariant,
108
+ getFabVariants,
109
+ } from './AtomicFab';
110
+
111
+ import {
112
+ AtomicFilter,
113
+ type AtomicFilterProps,
114
+ type FilterOption,
115
+ getFilterContainerStyle,
116
+ getClearAllContainerStyle,
117
+ getScrollContentContainerStyle,
118
+ } from './AtomicFilter';
119
+
120
+ import {
121
+ AtomicTouchable,
122
+ type AtomicTouchableProps,
123
+ type TouchableFeedback,
124
+ type FeedbackStrength,
125
+ type HitSlop,
126
+ TouchablePresets,
127
+ getOpacityValue,
128
+ normalizeHitSlop,
129
+ } from './AtomicTouchable';
130
+
131
+ // STEP 2: Re-export all components (for named imports)
132
+ export {
133
+ AtomicButton,
134
+ type AtomicButtonProps,
135
+ };
136
+
137
+ // Helper types extracted from ButtonVariantConfig
138
+
139
+ export {
140
+ AtomicText,
141
+ type AtomicTextProps,
142
+ };
143
+
144
+ export {
145
+ AtomicCard,
146
+ type AtomicCardProps,
147
+ type AtomicCardVariant,
148
+ type AtomicCardPadding,
149
+ };
150
+
151
+ export {
152
+ AtomicInput,
153
+ type AtomicInputProps,
154
+ type AtomicInputVariant,
155
+ type AtomicInputState,
156
+ type AtomicInputSize,
157
+ };
158
+
159
+ export {
160
+ AtomicIcon,
161
+ type AtomicIconProps,
162
+ type AtomicIconSize,
163
+ type AtomicIconColor,
164
+ };
165
+
166
+ export {
167
+ AtomicImage,
168
+ type AtomicImageProps,
169
+ };
170
+
171
+ export {
172
+ AtomicSwitch,
173
+ type AtomicSwitchProps,
174
+ };
175
+
176
+ export {
177
+ AtomicBadge,
178
+ type AtomicBadgeProps,
179
+ };
180
+
181
+ export {
182
+ AtomicFormError,
183
+ type AtomicFormErrorProps,
184
+ };
185
+
186
+ export {
187
+ AtomicAvatar,
188
+ type AtomicAvatarProps,
189
+ };
190
+
191
+ export {
192
+ AtomicChip,
193
+ type AtomicChipProps,
194
+ };
195
+
196
+ export {
197
+ AtomicDivider,
198
+ type AtomicDividerProps,
199
+ };
200
+
201
+ export {
202
+ AtomicSkeleton,
203
+ type AtomicSkeletonProps,
204
+ };
205
+
206
+ export {
207
+ AtomicProgress,
208
+ type AtomicProgressProps,
209
+ };
210
+
211
+ export {
212
+ AtomicAvatarGroup,
213
+ type AtomicAvatarGroupProps,
214
+ type AvatarData,
215
+ };
216
+
217
+ export {
218
+ AtomicFab,
219
+ type AtomicFabProps,
220
+ type FabSize,
221
+ type FabVariant,
222
+ getFabVariants,
223
+ };
224
+
225
+ export {
226
+ AtomicFilter,
227
+ type AtomicFilterProps,
228
+ type FilterOption,
229
+ getFilterContainerStyle,
230
+ getClearAllContainerStyle,
231
+ getScrollContentContainerStyle,
232
+ };
233
+
234
+ export {
235
+ AtomicTouchable,
236
+ type AtomicTouchableProps,
237
+ type TouchableFeedback,
238
+ type FeedbackStrength,
239
+ type HitSlop,
240
+ TouchablePresets,
241
+ getOpacityValue,
242
+ normalizeHitSlop,
243
+ };
244
+
245
+ /**
246
+ * Convenience re-exports for common patterns
247
+ */
248
+
249
+ // All atomic component types
250
+ export type AtomicComponentProps =
251
+ | AtomicButtonProps
252
+ | AtomicTextProps
253
+ | AtomicCardProps
254
+ | AtomicInputProps
255
+ | AtomicIconProps
256
+ | AtomicImageProps
257
+ | AtomicSwitchProps
258
+ | AtomicBadgeProps
259
+ | AtomicFormErrorProps
260
+ | AtomicAvatarProps
261
+ | AtomicChipProps
262
+ | AtomicDividerProps
263
+ | AtomicSkeletonProps
264
+ | AtomicProgressProps
265
+ | AtomicAvatarGroupProps
266
+ | AtomicFabProps
267
+ | AtomicFilterProps
268
+ | AtomicTouchableProps;
269
+
270
+ // All variant types for theme consistency
271
+ export type AtomicVariants = {
272
+ card: AtomicCardVariant;
273
+ input: AtomicInputVariant;
274
+ icon: AtomicIconSize;
275
+ };
276
+
277
+ // All color types for design system consistency
278
+ export type AtomicColors = AtomicIconColor;
279
+
280
+ /**
281
+ * Atomic component utilities
282
+ */
283
+ export const AtomicUtils = {
284
+ /**
285
+ * Get recommended component combinations for common UI patterns
286
+ */
287
+ getRecommendedCombinations: () => ({
288
+ // Card with header
289
+ cardWithHeader: {
290
+ card: { variant: 'elevated' as const, padding: 'lg' as const },
291
+ title: { variant: 'titleLarge' as const, color: 'primary' as const },
292
+ description: { variant: 'bodyMedium' as const, color: 'secondary' as const },
293
+ },
294
+
295
+ // Form field
296
+ formField: {
297
+ input: { variant: 'outlined' as const, size: 'md' as const },
298
+ label: { variant: 'labelMedium' as const, color: 'primary' as const },
299
+ helper: { variant: 'bodySmall' as const, color: 'secondary' as const },
300
+ },
301
+
302
+ // Action button
303
+ primaryAction: {
304
+ button: { variant: 'primary' as const, size: 'lg' as const },
305
+ text: { variant: 'labelLarge' as const, color: 'onPrimary' as const },
306
+ icon: { size: 'md' as const, color: 'onPrimary' as const },
307
+ },
308
+
309
+ // Secondary action
310
+ secondaryAction: {
311
+ button: { variant: 'outline' as const, size: 'md' as const },
312
+ text: { variant: 'labelMedium' as const, color: 'primary' as const },
313
+ icon: { size: 'sm' as const, color: 'primary' as const },
314
+ },
315
+ }),
316
+
317
+ /**
318
+ * Validate component prop combinations
319
+ */
320
+ validatePropCombination: (componentType: keyof AtomicVariants, props: any): boolean => {
321
+ // Add validation logic here for prop combinations
322
+ // This helps catch design system violations early
323
+ return true;
324
+ },
325
+
326
+ /**
327
+ * Get accessibility guidelines for component combinations
328
+ */
329
+ getAccessibilityGuidelines: () => ({
330
+ button: {
331
+ minimumTouchTarget: 48,
332
+ requiresAccessibilityLabel: true,
333
+ supportsAccessibilityHint: true,
334
+ },
335
+ input: {
336
+ requiresLabel: true,
337
+ supportsHelperText: true,
338
+ requiresAccessibilityLabel: true,
339
+ },
340
+ card: {
341
+ supportsAccessibilityRole: true,
342
+ canBeAccessibilityContainer: true,
343
+ },
344
+ text: {
345
+ supportsAccessibilityLabel: true,
346
+ respectsSystemTextSize: true,
347
+ },
348
+ icon: {
349
+ requiresAccessibilityLabel: true,
350
+ supportsAccessibilityHint: false,
351
+ },
352
+ }),
353
+ };
354
+
355
+ // STEP 3: Default export (now all components are available in scope)
356
+ const defaultExport = {
357
+ AtomicButton,
358
+ AtomicText,
359
+ AtomicCard,
360
+ AtomicInput,
361
+ AtomicIcon,
362
+ AtomicImage,
363
+ AtomicSwitch,
364
+ AtomicBadge,
365
+ AtomicFormError,
366
+ AtomicAvatar,
367
+ AtomicChip,
368
+ AtomicDivider,
369
+ AtomicSkeleton,
370
+ AtomicProgress,
371
+ AtomicAvatarGroup,
372
+ AtomicFab,
373
+ AtomicFilter,
374
+ AtomicTouchable,
375
+ AtomicUtils,
376
+ };
377
+
378
+ export default defaultExport;
@@ -0,0 +1,15 @@
1
+ import { useState } from 'react';
2
+
3
+ export const useInputState = (secureTextEntry: boolean = false) => {
4
+ const [isFocused, setIsFocused] = useState(false);
5
+ const [isPasswordVisible, setIsPasswordVisible] = useState(!secureTextEntry);
6
+
7
+ const togglePasswordVisibility = () => setIsPasswordVisible(!isPasswordVisible);
8
+
9
+ return {
10
+ isFocused,
11
+ setIsFocused,
12
+ isPasswordVisible,
13
+ togglePasswordVisibility,
14
+ };
15
+ };
@@ -0,0 +1,66 @@
1
+ import { ViewStyle, TextStyle } from 'react-native';
2
+ import { useAppDesignTokens } from '../../../hooks/useAppDesignTokens';
3
+ import { AtomicInputVariant, AtomicInputSize, AtomicInputState } from '../types';
4
+
5
+ type DesignTokens = ReturnType<typeof useAppDesignTokens>;
6
+
7
+ export const getContainerVariantStyles = (tokens: DesignTokens): Record<AtomicInputVariant, ViewStyle> => ({
8
+ outlined: {
9
+ borderWidth: 1,
10
+ borderRadius: 12,
11
+ borderColor: tokens.colors.outline,
12
+ },
13
+ filled: {
14
+ backgroundColor: tokens.colors.surfaceVariant,
15
+ borderRadius: 12,
16
+ borderBottomWidth: 2,
17
+ borderBottomColor: tokens.colors.outline,
18
+ },
19
+ underlined: {
20
+ borderBottomWidth: 1,
21
+ borderBottomColor: tokens.colors.outline,
22
+ backgroundColor: 'transparent',
23
+ },
24
+ });
25
+
26
+ export const containerSizeStyles: Record<AtomicInputSize, ViewStyle> = {
27
+ sm: { height: 40, paddingHorizontal: 12, paddingVertical: 8 },
28
+ md: { height: 56, paddingHorizontal: 16, paddingVertical: 16 },
29
+ lg: { height: 64, paddingHorizontal: 24, paddingVertical: 20 },
30
+ };
31
+
32
+ export const getInputSizeStyles = (tokens: DesignTokens): Record<AtomicInputSize, TextStyle> => ({
33
+ sm: { fontSize: tokens.typography.bodyMedium.fontSize },
34
+ md: { fontSize: tokens.typography.bodyLarge.fontSize },
35
+ lg: { fontSize: tokens.typography.bodyLarge.fontSize },
36
+ });
37
+
38
+ export const getLabelSizeStyles = (tokens: DesignTokens): Record<AtomicInputSize, TextStyle> => ({
39
+ sm: { fontSize: tokens.typography.bodySmall.fontSize },
40
+ md: { fontSize: tokens.typography.bodyMedium.fontSize },
41
+ lg: { fontSize: tokens.typography.bodyLarge.fontSize },
42
+ });
43
+
44
+ export const getStateStyles = (tokens: DesignTokens): Record<AtomicInputState, ViewStyle> => ({
45
+ default: {},
46
+ error: { borderColor: tokens.colors.error },
47
+ success: { borderColor: tokens.colors.success },
48
+ disabled: {
49
+ backgroundColor: tokens.colors.surfaceDisabled,
50
+ borderColor: tokens.colors.outlineDisabled,
51
+ },
52
+ });
53
+
54
+ export const getFocusStyles = (tokens: DesignTokens): Record<AtomicInputVariant, ViewStyle> => ({
55
+ outlined: { borderColor: tokens.colors.primary, borderWidth: 2 },
56
+ filled: { borderBottomColor: tokens.colors.primary, borderBottomWidth: 2 },
57
+ underlined: { borderBottomColor: tokens.colors.primary, borderBottomWidth: 2 },
58
+ });
59
+
60
+ export const getStateColor = (tokens: DesignTokens, state: AtomicInputState, isFocused: boolean, isDisabled: boolean): string => {
61
+ if (isDisabled) return tokens.colors.onSurfaceDisabled;
62
+ if (state === 'error') return tokens.colors.error;
63
+ if (state === 'success') return tokens.colors.success;
64
+ if (isFocused) return tokens.colors.primary;
65
+ return tokens.colors.surfaceVariant;
66
+ };
@@ -0,0 +1,25 @@
1
+ import { TextInputProps, ViewStyle, TextStyle } from 'react-native';
2
+
3
+ export type AtomicInputVariant = 'outlined' | 'filled' | 'underlined';
4
+ export type AtomicInputState = 'default' | 'error' | 'success' | 'disabled';
5
+ export type AtomicInputSize = 'sm' | 'md' | 'lg';
6
+
7
+ export interface AtomicInputProps extends Omit<TextInputProps, 'style'> {
8
+ variant?: AtomicInputVariant;
9
+ state?: AtomicInputState;
10
+ size?: AtomicInputSize;
11
+ label: string; // Required per CLAUDE.md Rule 16
12
+ helperText?: string;
13
+ leadingIcon?: React.ReactNode;
14
+ trailingIcon?: React.ReactNode;
15
+ showPasswordToggle?: boolean;
16
+ maxLength?: number;
17
+ showCharacterCount?: boolean;
18
+ disabled?: boolean;
19
+ style?: ViewStyle | ViewStyle[];
20
+ containerStyle?: ViewStyle | ViewStyle[];
21
+ inputStyle?: TextStyle | TextStyle[];
22
+ labelStyle?: TextStyle | TextStyle[];
23
+ helperTextStyle?: TextStyle | TextStyle[];
24
+ testID?: string;
25
+ }
@@ -0,0 +1,200 @@
1
+ import { ViewStyle, TextStyle } from 'react-native';
2
+ import { useAppDesignTokens } from '../../../hooks/useAppDesignTokens';
3
+ import { PickerSize } from '../types';
4
+ import { IOS_HIG, getMinTouchTarget } from '../../../utils/platformConstants';
5
+
6
+ type DesignTokens = ReturnType<typeof useAppDesignTokens>;
7
+
8
+ /**
9
+ * Picker container styles with iOS HIG compliance
10
+ *
11
+ * All picker sizes meet Apple's minimum touch target requirement of 44pt.
12
+ * @see https://developer.apple.com/design/human-interface-guidelines/layout
13
+ */
14
+ export const getPickerContainerStyles = (tokens: DesignTokens) => ({
15
+ base: {
16
+ flexDirection: 'row' as const,
17
+ alignItems: 'center' as const,
18
+ justifyContent: 'space-between' as const,
19
+ borderWidth: tokens.borders.width.thin,
20
+ borderColor: tokens.colors.border,
21
+ backgroundColor: tokens.colors.surface,
22
+ },
23
+ size: {
24
+ // ✅ iOS HIG Compliant: All sizes >= 44pt minimum touch target
25
+ sm: {
26
+ height: IOS_HIG.MIN_TOUCH_TARGET, // 44pt - iOS minimum
27
+ paddingHorizontal: tokens.spacing.sm,
28
+ borderRadius: tokens.borders.radius.sm,
29
+ },
30
+ md: {
31
+ height: getMinTouchTarget('input'), // 48pt - Recommended
32
+ paddingHorizontal: tokens.spacing.md,
33
+ borderRadius: tokens.borders.radius.md,
34
+ },
35
+ lg: {
36
+ height: 56, // 56pt - Large touch target
37
+ paddingHorizontal: tokens.spacing.lg,
38
+ borderRadius: tokens.borders.radius.md,
39
+ },
40
+ },
41
+ state: {
42
+ error: {
43
+ borderColor: tokens.colors.error,
44
+ borderWidth: tokens.borders.width.medium,
45
+ },
46
+ disabled: {
47
+ backgroundColor: tokens.colors.surfaceDisabled,
48
+ opacity: 0.6,
49
+ },
50
+ },
51
+ });
52
+
53
+ export const getPickerLabelStyles = (tokens: DesignTokens) => ({
54
+ base: {
55
+ marginBottom: tokens.spacing.xs,
56
+ color: tokens.colors.textPrimary,
57
+ fontWeight: '600' as const,
58
+ },
59
+ size: {
60
+ sm: tokens.typography.bodySmall,
61
+ md: tokens.typography.bodyMedium,
62
+ lg: tokens.typography.bodyLarge,
63
+ },
64
+ });
65
+
66
+ export const getPickerPlaceholderStyles = (tokens: DesignTokens) => ({
67
+ base: {
68
+ color: tokens.colors.textSecondary,
69
+ },
70
+ size: {
71
+ sm: tokens.typography.bodySmall,
72
+ md: tokens.typography.bodyMedium,
73
+ lg: tokens.typography.bodyLarge,
74
+ },
75
+ });
76
+
77
+ export const getPickerValueStyles = (tokens: DesignTokens) => ({
78
+ base: {
79
+ flex: 1,
80
+ color: tokens.colors.textPrimary,
81
+ },
82
+ size: {
83
+ sm: tokens.typography.bodySmall,
84
+ md: tokens.typography.bodyMedium,
85
+ lg: tokens.typography.bodyLarge,
86
+ },
87
+ });
88
+
89
+ export const getPickerErrorStyles = (tokens: DesignTokens): TextStyle => ({
90
+ marginTop: tokens.spacing.xs,
91
+ color: tokens.colors.error,
92
+ ...tokens.typography.bodySmall,
93
+ });
94
+
95
+ export const getModalOverlayStyles = (tokens: DesignTokens): ViewStyle => ({
96
+ flex: 1,
97
+ backgroundColor: tokens.colors.overlayMedium,
98
+ justifyContent: 'flex-start',
99
+ });
100
+
101
+ export const getModalContainerStyles = (tokens: DesignTokens, maxHeight: number): ViewStyle => ({
102
+ backgroundColor: tokens.colors.backgroundPrimary,
103
+ borderTopLeftRadius: tokens.borders.radius.lg,
104
+ borderTopRightRadius: tokens.borders.radius.lg,
105
+ maxHeight: maxHeight,
106
+ paddingBottom: tokens.spacing.lg,
107
+ });
108
+
109
+ export const getModalHeaderStyles = (tokens: DesignTokens): ViewStyle => ({
110
+ flexDirection: 'row',
111
+ alignItems: 'center',
112
+ justifyContent: 'space-between',
113
+ paddingHorizontal: tokens.spacing.lg,
114
+ paddingVertical: tokens.spacing.md,
115
+ borderBottomWidth: tokens.borders.width.thin,
116
+ borderBottomColor: tokens.colors.border,
117
+ });
118
+
119
+ export const getModalTitleStyles = (tokens: DesignTokens): TextStyle => ({
120
+ ...tokens.typography.titleLarge,
121
+ color: tokens.colors.textPrimary,
122
+ fontWeight: '600',
123
+ });
124
+
125
+ export const getSearchContainerStyles = (tokens: DesignTokens): ViewStyle => ({
126
+ flexDirection: 'row',
127
+ alignItems: 'center',
128
+ backgroundColor: tokens.colors.surfaceVariant,
129
+ paddingHorizontal: tokens.spacing.md,
130
+ paddingVertical: tokens.spacing.sm,
131
+ marginHorizontal: tokens.spacing.lg,
132
+ marginTop: tokens.spacing.md,
133
+ borderRadius: tokens.borders.radius.md,
134
+ });
135
+
136
+ export const getSearchInputStyles = (tokens: DesignTokens): TextStyle => ({
137
+ flex: 1,
138
+ marginLeft: tokens.spacing.sm,
139
+ ...tokens.typography.bodyMedium,
140
+ color: tokens.colors.textPrimary,
141
+ });
142
+
143
+ export const getOptionContainerStyles = (tokens: DesignTokens, isSelected: boolean, isDisabled: boolean): ViewStyle => ({
144
+ flexDirection: 'row',
145
+ alignItems: 'center',
146
+ paddingHorizontal: tokens.spacing.lg,
147
+ paddingVertical: tokens.spacing.md,
148
+ backgroundColor: isSelected ? tokens.colors.primaryContainer : 'transparent',
149
+ opacity: isDisabled ? 0.5 : 1,
150
+ });
151
+
152
+ export const getOptionTextStyles = (tokens: DesignTokens, isSelected: boolean): TextStyle => ({
153
+ flex: 1,
154
+ marginLeft: tokens.spacing.sm,
155
+ ...tokens.typography.bodyLarge,
156
+ color: isSelected ? tokens.colors.primary : tokens.colors.textPrimary,
157
+ fontWeight: isSelected ? '600' : '400',
158
+ });
159
+
160
+ export const getOptionDescriptionStyles = (tokens: DesignTokens): TextStyle => ({
161
+ ...tokens.typography.bodySmall,
162
+ color: tokens.colors.textSecondary,
163
+ marginLeft: tokens.spacing.sm,
164
+ marginTop: tokens.spacing.xs,
165
+ });
166
+
167
+ export const getEmptyStateStyles = (tokens: DesignTokens): ViewStyle => ({
168
+ alignItems: 'center',
169
+ justifyContent: 'center',
170
+ paddingVertical: tokens.spacing.xxl,
171
+ });
172
+
173
+ export const getEmptyStateTextStyles = (tokens: DesignTokens): TextStyle => ({
174
+ ...tokens.typography.bodyLarge,
175
+ color: tokens.colors.textSecondary,
176
+ textAlign: 'center',
177
+ marginTop: tokens.spacing.md,
178
+ });
179
+
180
+ export const getChipContainerStyles = (tokens: DesignTokens): ViewStyle => ({
181
+ flexDirection: 'row',
182
+ flexWrap: 'wrap',
183
+ gap: tokens.spacing.xs,
184
+ marginTop: tokens.spacing.xs,
185
+ });
186
+
187
+ export const getChipStyles = (tokens: DesignTokens): ViewStyle => ({
188
+ flexDirection: 'row',
189
+ alignItems: 'center',
190
+ backgroundColor: tokens.colors.primaryContainer,
191
+ paddingHorizontal: tokens.spacing.sm,
192
+ paddingVertical: tokens.spacing.xs,
193
+ borderRadius: tokens.borders.radius.sm,
194
+ });
195
+
196
+ export const getChipTextStyles = (tokens: DesignTokens): TextStyle => ({
197
+ ...tokens.typography.bodySmall,
198
+ color: tokens.colors.primary,
199
+ marginRight: tokens.spacing.xs,
200
+ });