@umituz/react-native-design-system 4.23.80 → 4.23.82

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 (77) hide show
  1. package/package.json +3 -3
  2. package/src/atoms/AtomicInput.tsx +11 -48
  3. package/src/atoms/AtomicPicker.tsx +19 -94
  4. package/src/atoms/EmptyState.tsx +1 -1
  5. package/src/atoms/icon/iconStore.ts +1 -1
  6. package/src/atoms/picker/components/PickerModal.tsx +40 -121
  7. package/src/device/infrastructure/services/PersistentDeviceIdService.ts +4 -4
  8. package/src/device/presentation/hooks/useDeviceInfo.ts +55 -149
  9. package/src/haptics/infrastructure/services/HapticService.ts +1 -1
  10. package/src/image/index.ts +2 -1
  11. package/src/image/presentation/hooks/useImageBatch.ts +2 -1
  12. package/src/infinite-scroll/presentation/components/infinite-scroll-list.tsx +1 -1
  13. package/src/infinite-scroll/presentation/hooks/pagination.helper.ts +0 -5
  14. package/src/infinite-scroll/presentation/hooks/useInfiniteScroll.ts +4 -54
  15. package/src/init/createAppInitializer.ts +1 -1
  16. package/src/init/env/createEnvConfig.ts +0 -1
  17. package/src/init/useAppInitialization.ts +0 -1
  18. package/src/layouts/ScreenHeader/ScreenHeader.tsx +1 -1
  19. package/src/media/infrastructure/services/CardMediaOptimizerService.ts +1 -1
  20. package/src/media/infrastructure/services/CardMediaUploadService.ts +0 -1
  21. package/src/media/presentation/hooks/useCardMediaGeneration.ts +1 -1
  22. package/src/media/presentation/hooks/useCardMediaUpload.ts +1 -1
  23. package/src/media/presentation/hooks/useCardMediaValidation.ts +1 -1
  24. package/src/media/presentation/hooks/useCardMultimediaFlashcard.ts +1 -1
  25. package/src/media/presentation/hooks/useMedia.ts +0 -1
  26. package/src/media/presentation/hooks/useMediaGeneration.ts +1 -1
  27. package/src/media/presentation/hooks/useMediaUpload.ts +1 -1
  28. package/src/media/presentation/hooks/useMediaValidation.ts +1 -1
  29. package/src/media/presentation/hooks/useMultimediaFlashcard.ts +1 -1
  30. package/src/molecules/BaseModal.tsx +2 -3
  31. package/src/molecules/ConfirmationModalContent.tsx +1 -1
  32. package/src/molecules/ConfirmationModalMain.tsx +1 -1
  33. package/src/molecules/bottom-sheet/components/BottomSheetModal.tsx +1 -3
  34. package/src/molecules/bottom-sheet/components/filter/FilterBottomSheet.tsx +100 -179
  35. package/src/molecules/calendar/infrastructure/stores/useCalendarEvents.ts +0 -1
  36. package/src/molecules/confirmation-modal/useConfirmationModal.ts +1 -1
  37. package/src/molecules/countdown/components/Countdown.tsx +1 -1
  38. package/src/molecules/navigation/StackNavigator.tsx +1 -1
  39. package/src/molecules/navigation/TabsNavigator.tsx +1 -1
  40. package/src/molecules/navigation/types.ts +2 -2
  41. package/src/molecules/navigation/utils/AppNavigation.ts +0 -8
  42. package/src/molecules/splash/components/SplashScreen.tsx +0 -4
  43. package/src/offline/infrastructure/events/NetworkEvents.ts +2 -2
  44. package/src/offline/infrastructure/utils/healthCheck.ts +1 -6
  45. package/src/offline/presentation/hooks/useOffline.ts +1 -2
  46. package/src/offline/presentation/hooks/useOfflineWithMutations.ts +1 -3
  47. package/src/onboarding/index.ts +0 -1
  48. package/src/onboarding/infrastructure/hooks/useOnboardingNavigation.ts +0 -1
  49. package/src/onboarding/infrastructure/storage/actions/storageHelpers.ts +1 -3
  50. package/src/onboarding/presentation/hooks/useOnboardingScreenHandlers.ts +2 -4
  51. package/src/onboarding/presentation/hooks/useOnboardingScreenState.ts +0 -1
  52. package/src/onboarding/presentation/screens/OnboardingScreen.tsx +0 -3
  53. package/src/organisms/FormContainer.tsx +1 -1
  54. package/src/services/api/ApiClient.ts +42 -135
  55. package/src/storage/cache/domain/Cache.ts +0 -2
  56. package/src/storage/cache/domain/__tests__/ErrorHandler.test.ts +8 -8
  57. package/src/storage/cache/infrastructure/TTLCache.ts +0 -3
  58. package/src/storage/domain/utils/devUtils.ts +3 -6
  59. package/src/storage/infrastructure/adapters/StorageService.ts +0 -3
  60. package/src/storage/infrastructure/repositories/BaseStorageOperations.ts +0 -1
  61. package/src/tanstack/domain/config/QueryClientAccessor.ts +0 -1
  62. package/src/tanstack/domain/repositories/BaseRepository.ts +4 -4
  63. package/src/tanstack/domain/repositories/IBaseRepository.ts +3 -5
  64. package/src/tanstack/domain/repositories/RepositoryFactory.ts +0 -2
  65. package/src/tanstack/domain/repositories/mixins/repositoryInvalidationMethods.ts +10 -11
  66. package/src/tanstack/domain/repositories/mixins/repositoryQueryMethods.ts +11 -11
  67. package/src/tanstack/domain/utils/ErrorHelpers.ts +1 -2
  68. package/src/tanstack/infrastructure/config/PersisterConfig.ts +6 -13
  69. package/src/tanstack/infrastructure/config/QueryClientConfig.ts +0 -13
  70. package/src/tanstack/infrastructure/monitoring/DevMonitorLogger.ts +0 -5
  71. package/src/tanstack/presentation/hooks/useInvalidateQueries.ts +0 -4
  72. package/src/tanstack/presentation/hooks/useOptimisticUpdate.ts +0 -2
  73. package/src/tanstack/presentation/hooks/usePrefetch.ts +18 -119
  74. package/src/theme/core/CustomColors.ts +4 -122
  75. package/src/theme/infrastructure/storage/ThemeStorage.ts +0 -1
  76. package/src/typography/presentation/utils/textColorUtils.ts +36 -163
  77. package/src/tanstack/presentation/hooks/utils/prefetchLogger.ts +0 -27
@@ -82,8 +82,7 @@ export function createPersister(options: PersisterFactoryOptions = {}): Persiste
82
82
  // Validate cache version
83
83
  if (parsed.version !== busterVersion) {
84
84
  if (__DEV__) {
85
-
86
- console.log(
85
+ console.warn(
87
86
  `[TanStack Query] Cache version mismatch. Expected: ${busterVersion}, Got: ${parsed.version}`,
88
87
  );
89
88
  }
@@ -94,8 +93,7 @@ export function createPersister(options: PersisterFactoryOptions = {}): Persiste
94
93
  const age = Date.now() - parsed.timestamp;
95
94
  if (age > maxAge) {
96
95
  if (__DEV__) {
97
-
98
- console.log(`[TanStack Query] Cache expired. Age: ${age}ms, Max: ${maxAge}ms`);
96
+ console.warn(`[TanStack Query] Cache age exceeded maxAge: ${maxAge}ms`);
99
97
  }
100
98
  return undefined;
101
99
  }
@@ -103,8 +101,7 @@ export function createPersister(options: PersisterFactoryOptions = {}): Persiste
103
101
  return parsed.data;
104
102
  } catch (error) {
105
103
  if (__DEV__) {
106
-
107
- console.error('[TanStack Query] Failed to deserialize cache:', error);
104
+ console.error('[TanStack Query] Error deserializing cache:', error);
108
105
  }
109
106
  return undefined;
110
107
  }
@@ -125,13 +122,11 @@ export async function clearPersistedCache(keyPrefix: string = 'tanstack-query'):
125
122
  try {
126
123
  await storageService.removeItem(`${keyPrefix}-cache`);
127
124
  if (__DEV__) {
128
-
129
- console.log(`[TanStack Query] Cleared persisted cache: ${keyPrefix}`);
125
+ console.log(`[TanStack Query] Cleared persisted cache for keyPrefix: ${keyPrefix}`);
130
126
  }
131
127
  } catch (error) {
132
128
  if (__DEV__) {
133
-
134
- console.error('[TanStack Query] Failed to clear persisted cache:', error);
129
+ console.error('[TanStack Query] Error clearing persisted cache:', error);
135
130
  }
136
131
  }
137
132
  }
@@ -143,7 +138,6 @@ export async function clearPersistedCache(keyPrefix: string = 'tanstack-query'):
143
138
  * @example
144
139
  * ```typescript
145
140
  * const size = await getPersistedCacheSize('myapp');
146
- * console.log(`Cache size: ${size} bytes`);
147
141
  * ```
148
142
  */
149
143
  export async function getPersistedCacheSize(
@@ -154,8 +148,7 @@ export async function getPersistedCacheSize(
154
148
  return data ? new Blob([data]).size : 0;
155
149
  } catch (error) {
156
150
  if (__DEV__) {
157
-
158
- console.error('[TanStack Query] Failed to get cache size:', error);
151
+ console.error('[TanStack Query] Error getting persisted cache size:', error);
159
152
  }
160
153
  return 0;
161
154
  }
@@ -86,12 +86,6 @@ export interface QueryClientFactoryOptions {
86
86
  * @default 3
87
87
  */
88
88
  defaultRetry?: boolean | number | RetryFunction;
89
-
90
- /**
91
- * Enable development mode logging
92
- * @default __DEV__
93
- */
94
- enableDevLogging?: boolean;
95
89
  }
96
90
 
97
91
  /**
@@ -110,7 +104,6 @@ export function createQueryClient(options: QueryClientFactoryOptions = {}): Quer
110
104
  defaultStaleTime = DEFAULT_STALE_TIME.SHORT,
111
105
  defaultGcTime = DEFAULT_GC_TIME.LONG,
112
106
  defaultRetry = DEFAULT_RETRY.STANDARD,
113
- enableDevLogging = __DEV__,
114
107
  } = options;
115
108
 
116
109
  return new QueryClient({
@@ -125,12 +118,6 @@ export function createQueryClient(options: QueryClientFactoryOptions = {}): Quer
125
118
  },
126
119
  mutations: {
127
120
  retry: DEFAULT_RETRY.MINIMAL,
128
- onError: (error: Error) => {
129
- if (enableDevLogging) {
130
-
131
- console.error('[TanStack Query] Mutation error:', error);
132
- }
133
- },
134
121
  },
135
122
  },
136
123
  });
@@ -8,7 +8,6 @@ import type { QueryMetrics, CacheStats } from './DevMonitor.types';
8
8
  export class DevMonitorLogger {
9
9
  static logInit(): void {
10
10
  if (__DEV__) {
11
- console.log('[TanStack DevMonitor] Monitoring initialized');
12
11
  }
13
12
  }
14
13
 
@@ -22,19 +21,16 @@ export class DevMonitorLogger {
22
21
 
23
22
  static logAttached(): void {
24
23
  if (__DEV__) {
25
- console.log('[TanStack DevMonitor] Attached to QueryClient');
26
24
  }
27
25
  }
28
26
 
29
27
  static logMethodsCleared(): void {
30
28
  if (__DEV__) {
31
- console.log('[TanStack DevMonitor] Metrics cleared');
32
29
  }
33
30
  }
34
31
 
35
32
  static logReset(): void {
36
33
  if (__DEV__) {
37
- console.log('[TanStack DevMonitor] Reset');
38
34
  }
39
35
  }
40
36
 
@@ -53,7 +49,6 @@ export class DevMonitorLogger {
53
49
  }
54
50
 
55
51
  if (slowQueries.length > 0) {
56
- console.warn(`Found ${slowQueries.length} slow queries:`);
57
52
  console.table(
58
53
  slowQueries.map((m) => ({
59
54
  queryKey: JSON.stringify(m.queryKey),
@@ -36,7 +36,6 @@ export function useInvalidateQueries() {
36
36
 
37
37
  if (__DEV__) {
38
38
 
39
- console.log('[TanStack Query] Invalidated queries:', queryKey);
40
39
  }
41
40
  },
42
41
  [queryClient],
@@ -65,7 +64,6 @@ export function useInvalidateMultipleQueries() {
65
64
 
66
65
  if (__DEV__) {
67
66
 
68
- console.log('[TanStack Query] Invalidated multiple queries:', queryKeys);
69
67
  }
70
68
  },
71
69
  [queryClient],
@@ -93,7 +91,6 @@ export function useRemoveQueries() {
93
91
 
94
92
  if (__DEV__) {
95
93
 
96
- console.log('[TanStack Query] Removed queries:', queryKey);
97
94
  }
98
95
  },
99
96
  [queryClient],
@@ -120,7 +117,6 @@ export function useResetQueries() {
120
117
 
121
118
  if (__DEV__) {
122
119
 
123
- console.log('[TanStack Query] Reset queries:', queryKey);
124
120
  }
125
121
  },
126
122
  [queryClient],
@@ -39,7 +39,6 @@ export function useOptimisticUpdate<TData = unknown, TVariables = unknown, TErro
39
39
 
40
40
  if (__DEV__) {
41
41
 
42
- console.log('[TanStack Query] Optimistic update applied:', queryKey);
43
42
  }
44
43
  }
45
44
 
@@ -53,7 +52,6 @@ export function useOptimisticUpdate<TData = unknown, TVariables = unknown, TErro
53
52
 
54
53
  if (__DEV__) {
55
54
 
56
- console.error('[TanStack Query] Optimistic update rolled back:', error);
57
55
  }
58
56
  }
59
57
 
@@ -9,36 +9,16 @@ import { useQueryClient } from '@tanstack/react-query';
9
9
  import { useCallback, useEffect, useRef } from 'react';
10
10
  import type { QueryKey, QueryFunction } from '@tanstack/react-query';
11
11
  import type { PrefetchOptions } from './types/prefetchTypes';
12
- import { logPrefetch, logPrefetchMultiple } from './utils/prefetchLogger';
13
12
 
14
13
  export type { PrefetchOptions };
15
14
 
16
- /**
17
- * Hook for prefetching query data
18
- *
19
- * Useful for:
20
- * - Preloading data before navigation
21
- * - Warming up cache on mount
22
- * - Background data refresh
23
- *
24
- * @example
25
- * ```typescript
26
- * function UserProfileList({ userIds }: { userIds: string[] }) {
27
- * const prefetchUser = usePrefetchQuery(['user'], async (id) => fetchUser(id));
28
- *
29
- * return (
30
- * <FlatList
31
- * data={userIds}
32
- * onViewableItemsChanged={({ viewableItems }) => {
33
- * viewableItems.forEach((item) => {
34
- * prefetchUser(item.key);
35
- * });
36
- * }}
37
- * />
38
- * );
39
- * }
40
- * ```
41
- */
15
+ function getPrefetchConfig(options: PrefetchOptions) {
16
+ return {
17
+ staleTime: options.staleTime,
18
+ gcTime: options.gcTime,
19
+ };
20
+ }
21
+
42
22
  export function usePrefetchQuery<
43
23
  TQueryFnData = unknown,
44
24
  TVariables = string | number,
@@ -50,11 +30,9 @@ export function usePrefetchQuery<
50
30
  const queryClient = useQueryClient();
51
31
  const prefetchingRef = useRef(new Set<TVariables>());
52
32
 
53
- const prefetch = useCallback(
33
+ return useCallback(
54
34
  async (variables: TVariables) => {
55
- if (prefetchingRef.current.has(variables)) {
56
- return;
57
- }
35
+ if (prefetchingRef.current.has(variables)) return;
58
36
 
59
37
  prefetchingRef.current.add(variables);
60
38
 
@@ -62,42 +40,16 @@ export function usePrefetchQuery<
62
40
  await queryClient.prefetchQuery({
63
41
  queryKey: [...queryKey, variables],
64
42
  queryFn: () => queryFn(variables),
65
- staleTime: options.staleTime,
66
- gcTime: options.gcTime,
43
+ ...getPrefetchConfig(options),
67
44
  });
68
-
69
- logPrefetch('Prefetched:', [...queryKey, variables]);
70
45
  } finally {
71
46
  prefetchingRef.current.delete(variables);
72
47
  }
73
48
  },
74
- [queryClient, queryKey, queryFn, options.staleTime, options.gcTime],
49
+ [queryClient, queryKey, queryFn, options],
75
50
  );
76
-
77
- return prefetch;
78
51
  }
79
52
 
80
- /**
81
- * Hook for prefetching infinite query data
82
- *
83
- * Useful for:
84
- * - Preloading infinite scroll content
85
- * - Warming up paginated feeds
86
- *
87
- * @example
88
- * ```typescript
89
- * function FeedScreen() {
90
- * const prefetchFeed = usePrefetchInfiniteQuery(
91
- * ['feed'],
92
- * ({ pageParam }) => fetchFeed({ cursor: pageParam })
93
- * );
94
- *
95
- * useEffect(() => {
96
- * prefetchFeed();
97
- * }, []);
98
- * }
99
- * ```
100
- */
101
53
  export function usePrefetchInfiniteQuery<
102
54
  TQueryFnData = unknown,
103
55
  TPageParam = unknown,
@@ -110,10 +62,8 @@ export function usePrefetchInfiniteQuery<
110
62
  const queryClient = useQueryClient();
111
63
  const hasPrefetchedRef = useRef(false);
112
64
 
113
- const prefetch = useCallback(async () => {
114
- if (hasPrefetchedRef.current) {
115
- return;
116
- }
65
+ return useCallback(async () => {
66
+ if (hasPrefetchedRef.current) return;
117
67
 
118
68
  hasPrefetchedRef.current = true;
119
69
 
@@ -121,38 +71,15 @@ export function usePrefetchInfiniteQuery<
121
71
  await queryClient.prefetchInfiniteQuery({
122
72
  queryKey,
123
73
  queryFn,
124
- staleTime: options.staleTime,
125
- gcTime: options.gcTime,
74
+ ...getPrefetchConfig(options),
126
75
  initialPageParam,
127
76
  });
128
-
129
- logPrefetch('Prefetched infinite:', queryKey);
130
77
  } catch {
131
78
  hasPrefetchedRef.current = false;
132
79
  }
133
- }, [queryClient, queryKey, queryFn, options.staleTime, options.gcTime, initialPageParam]);
134
-
135
- return prefetch;
80
+ }, [queryClient, queryKey, queryFn, options, initialPageParam]);
136
81
  }
137
82
 
138
- /**
139
- * Hook for prefetching on mount
140
- *
141
- * Convenience hook that prefetches data when component mounts
142
- *
143
- * @example
144
- * ```typescript
145
- * function UserProfile({ userId }: { userId: string }) {
146
- * usePrefetchOnMount(
147
- * ['user', userId],
148
- * () => fetchUser(userId),
149
- * { staleTime: TIME_MS.MINUTE }
150
- * );
151
- *
152
- * // Component will prefetch user data on mount
153
- * }
154
- * ```
155
- */
156
83
  export function usePrefetchOnMount<TData = unknown>(
157
84
  queryKey: QueryKey,
158
85
  queryFn: () => Promise<TData>,
@@ -164,32 +91,11 @@ export function usePrefetchOnMount<TData = unknown>(
164
91
  queryClient.prefetchQuery({
165
92
  queryKey,
166
93
  queryFn,
167
- staleTime: options.staleTime,
168
- gcTime: options.gcTime,
94
+ ...getPrefetchConfig(options),
169
95
  });
170
-
171
- logPrefetch('Prefetched on mount:', queryKey);
172
- }, [queryClient, queryKey, queryFn, options.staleTime, options.gcTime]);
96
+ }, [queryClient, queryKey, queryFn, options]);
173
97
  }
174
98
 
175
- /**
176
- * Hook for prefetching multiple queries
177
- *
178
- * @example
179
- * ```typescript
180
- * function Dashboard() {
181
- * const prefetchMultiple = usePrefetchMultiple();
182
- *
183
- * useEffect(() => {
184
- * prefetchMultiple([
185
- * { queryKey: ['user'], queryFn: fetchUser },
186
- * { queryKey: ['posts'], queryFn: fetchPosts },
187
- * { queryKey: ['notifications'], queryFn: fetchNotifications },
188
- * ]);
189
- * }, []);
190
- * }
191
- * ```
192
- */
193
99
  export function usePrefetchMultiple<TData = unknown>() {
194
100
  const queryClient = useQueryClient();
195
101
 
@@ -202,16 +108,9 @@ export function usePrefetchMultiple<TData = unknown>() {
202
108
  }>) => {
203
109
  await Promise.all(
204
110
  queries.map(({ queryKey, queryFn, staleTime, gcTime }) =>
205
- queryClient.prefetchQuery({
206
- queryKey,
207
- queryFn,
208
- staleTime,
209
- gcTime,
210
- }),
111
+ queryClient.prefetchQuery({ queryKey, queryFn, staleTime, gcTime }),
211
112
  ),
212
113
  );
213
-
214
- logPrefetchMultiple(queries.length);
215
114
  },
216
115
  [queryClient],
217
116
  );
@@ -2,43 +2,21 @@
2
2
  * Custom Colors Types
3
3
  *
4
4
  * Types for custom theme color overrides
5
- *
6
- * ARCHITECTURE:
7
- * - Apps provide CustomThemeColors to DesignSystemProvider
8
- * - These colors override the default palette
9
- * - Supports both light and dark mode overrides
10
- * - Apps control their own brand colors completely
11
- *
12
- * BEST PRACTICES (based on Shopify Restyle, React Native Paper, Tamagui):
13
- * - All color keys are optional - only override what you need
14
- * - Provide separate light/dark palettes for proper theme switching
15
- * - Use semantic color names (primary, surface, etc.) not literal colors
16
5
  */
17
6
 
18
7
  import type { ColorPalette } from './ColorPalette';
19
8
  import { isValidHexColor } from './colors/ColorUtils';
20
9
 
21
- /**
22
- * Complete custom theme colors - can override ANY color in the palette
23
- * All properties are optional - apps only provide what they want to customize
24
- */
25
10
  export interface CustomThemeColors {
26
- // PRIMARY BRAND COLORS
27
11
  primary?: string;
28
12
  primaryLight?: string;
29
13
  primaryDark?: string;
30
-
31
- // SECONDARY COLORS
32
14
  secondary?: string;
33
15
  secondaryLight?: string;
34
16
  secondaryDark?: string;
35
-
36
- // ACCENT COLORS
37
17
  accent?: string;
38
18
  accentLight?: string;
39
19
  accentDark?: string;
40
-
41
- // ON-COLORS (text on colored backgrounds - CRITICAL for contrast)
42
20
  onPrimary?: string;
43
21
  onSecondary?: string;
44
22
  onSuccess?: string;
@@ -49,21 +27,15 @@ export interface CustomThemeColors {
49
27
  onBackground?: string;
50
28
  onSurfaceDisabled?: string;
51
29
  onSurfaceVariant?: string;
52
-
53
- // CONTAINER COLORS
54
30
  primaryContainer?: string;
55
31
  onPrimaryContainer?: string;
56
32
  secondaryContainer?: string;
57
33
  onSecondaryContainer?: string;
58
34
  errorContainer?: string;
59
35
  onErrorContainer?: string;
60
-
61
- // OUTLINE COLORS
62
36
  outline?: string;
63
37
  outlineVariant?: string;
64
38
  outlineDisabled?: string;
65
-
66
- // SEMANTIC UI COLORS
67
39
  success?: string;
68
40
  successLight?: string;
69
41
  successDark?: string;
@@ -76,151 +48,61 @@ export interface CustomThemeColors {
76
48
  info?: string;
77
49
  infoLight?: string;
78
50
  infoDark?: string;
79
-
80
- // SEMANTIC CONTAINER COLORS
81
51
  successContainer?: string;
82
52
  onSuccessContainer?: string;
83
53
  warningContainer?: string;
84
54
  onWarningContainer?: string;
85
55
  infoContainer?: string;
86
56
  onInfoContainer?: string;
87
-
88
- // BACKGROUND COLORS
89
57
  backgroundPrimary?: string;
90
58
  backgroundSecondary?: string;
91
-
92
- // SURFACE COLORS
93
59
  surface?: string;
94
60
  surfaceVariant?: string;
95
61
  surfaceSecondary?: string;
96
62
  surfaceDisabled?: string;
97
-
98
- // TEXT COLORS
99
63
  textPrimary?: string;
100
64
  textSecondary?: string;
101
65
  textTertiary?: string;
102
66
  textDisabled?: string;
103
67
  textInverse?: string;
104
-
105
- // BORDER COLORS
106
68
  border?: string;
107
69
  borderLight?: string;
108
70
  borderMedium?: string;
109
71
  borderFocus?: string;
110
72
  borderDisabled?: string;
111
-
112
- // COMPONENT-SPECIFIC COLORS
113
73
  buttonPrimary?: string;
114
74
  buttonSecondary?: string;
115
75
  inputBackground?: string;
116
76
  inputBorder?: string;
117
77
  cardBackground?: string;
118
-
119
- // SPECIAL & UTILITY COLORS
120
78
  transparent?: string;
121
79
  black?: string;
122
80
  white?: string;
123
81
  modalOverlay?: string;
124
82
  }
125
83
 
126
- /**
127
- * Validate custom colors object
128
- * @param customColors - Custom colors to validate
129
- * @returns true if all colors are valid hex format
130
- */
131
84
  export const validateCustomColors = (customColors: CustomThemeColors): boolean => {
132
85
  const colorValues = Object.values(customColors).filter(Boolean) as string[];
133
-
134
- for (const color of colorValues) {
135
- if (!isValidHexColor(color)) {
136
- return false;
137
- }
138
- }
139
-
140
- return true;
86
+ return colorValues.every((color) => isValidHexColor(color));
141
87
  };
142
88
 
143
- /**
144
- * Apply custom colors to color palette
145
- *
146
- * This function takes a base palette and merges custom colors into it.
147
- * Apps can override ANY color key - the system simply spreads custom values
148
- * over the base palette.
149
- *
150
- * @param palette - Base color palette (light or dark)
151
- * @param customColors - Custom colors to apply (partial override)
152
- * @returns Color palette with custom colors applied
153
- */
154
89
  export const applyCustomColors = (
155
90
  palette: ColorPalette,
156
91
  customColors?: CustomThemeColors,
157
92
  ): ColorPalette => {
158
- if (!customColors) {
159
- return palette;
160
- }
93
+ if (!customColors) return palette;
161
94
 
162
- // Validate custom colors
163
95
  if (!validateCustomColors(customColors)) {
164
- if (__DEV__) {
165
- console.warn('[DesignSystem] Invalid custom colors provided - using default palette');
166
- }
167
96
  return palette;
168
97
  }
169
98
 
170
- // Start with base palette
171
- const result: Partial<ColorPalette> = {
172
- ...palette,
173
- };
174
-
175
- // Apply ALL custom colors dynamically
176
- // This approach allows any color key to be overridden
177
- const colorKeys = Object.keys(customColors) as (keyof CustomThemeColors)[];
99
+ const result: Partial<ColorPalette> = { ...palette };
178
100
 
179
- for (const key of colorKeys) {
180
- const value = customColors[key];
101
+ for (const [key, value] of Object.entries(customColors)) {
181
102
  if (value !== undefined) {
182
- // Direct assignment for matching keys
183
103
  (result as Record<string, string>)[key] = value;
184
104
  }
185
105
  }
186
106
 
187
- // Apply smart defaults and aliases
188
- // Primary -> buttonPrimary (if buttonPrimary not explicitly set)
189
- if (customColors.primary && !customColors.buttonPrimary) {
190
- result.buttonPrimary = customColors.primary;
191
- }
192
-
193
- // Secondary -> buttonSecondary (if buttonSecondary not explicitly set)
194
- if (customColors.secondary && !customColors.buttonSecondary) {
195
- result.buttonSecondary = customColors.secondary;
196
- }
197
-
198
- // Background aliases
199
- if (customColors.backgroundPrimary) {
200
- result.background = customColors.backgroundPrimary;
201
- }
202
-
203
- // Surface aliases
204
- if (customColors.surface) {
205
- result.card = customColors.surface;
206
- result.cardBackground = customColors.surface;
207
- }
208
- if (customColors.surfaceVariant && !customColors.surfaceSecondary) {
209
- result.surfaceSecondary = customColors.surfaceVariant;
210
- }
211
-
212
- // Text aliases
213
- if (customColors.textPrimary) {
214
- result.text = customColors.textPrimary;
215
- }
216
-
217
- // Input aliases
218
- if (customColors.inputBorder && !result.inputBorder) {
219
- result.inputBorder = customColors.inputBorder;
220
- }
221
- if (customColors.border && !customColors.inputBorder) {
222
- result.inputBorder = customColors.border;
223
- }
224
-
225
107
  return result as ColorPalette;
226
108
  };
@@ -62,7 +62,6 @@ export class ThemeStorage {
62
62
  }
63
63
 
64
64
  if (__DEV__) {
65
- console.warn('[ThemeStorage] Invalid or corrupted custom colors data - ignoring');
66
65
  }
67
66
 
68
67
  return undefined;