@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.
- package/package.json +3 -3
- package/src/atoms/AtomicInput.tsx +11 -48
- package/src/atoms/AtomicPicker.tsx +19 -94
- package/src/atoms/EmptyState.tsx +1 -1
- package/src/atoms/icon/iconStore.ts +1 -1
- package/src/atoms/picker/components/PickerModal.tsx +40 -121
- package/src/device/infrastructure/services/PersistentDeviceIdService.ts +4 -4
- package/src/device/presentation/hooks/useDeviceInfo.ts +55 -149
- package/src/haptics/infrastructure/services/HapticService.ts +1 -1
- package/src/image/index.ts +2 -1
- package/src/image/presentation/hooks/useImageBatch.ts +2 -1
- package/src/infinite-scroll/presentation/components/infinite-scroll-list.tsx +1 -1
- package/src/infinite-scroll/presentation/hooks/pagination.helper.ts +0 -5
- package/src/infinite-scroll/presentation/hooks/useInfiniteScroll.ts +4 -54
- package/src/init/createAppInitializer.ts +1 -1
- package/src/init/env/createEnvConfig.ts +0 -1
- package/src/init/useAppInitialization.ts +0 -1
- package/src/layouts/ScreenHeader/ScreenHeader.tsx +1 -1
- package/src/media/infrastructure/services/CardMediaOptimizerService.ts +1 -1
- package/src/media/infrastructure/services/CardMediaUploadService.ts +0 -1
- package/src/media/presentation/hooks/useCardMediaGeneration.ts +1 -1
- package/src/media/presentation/hooks/useCardMediaUpload.ts +1 -1
- package/src/media/presentation/hooks/useCardMediaValidation.ts +1 -1
- package/src/media/presentation/hooks/useCardMultimediaFlashcard.ts +1 -1
- package/src/media/presentation/hooks/useMedia.ts +0 -1
- package/src/media/presentation/hooks/useMediaGeneration.ts +1 -1
- package/src/media/presentation/hooks/useMediaUpload.ts +1 -1
- package/src/media/presentation/hooks/useMediaValidation.ts +1 -1
- package/src/media/presentation/hooks/useMultimediaFlashcard.ts +1 -1
- package/src/molecules/BaseModal.tsx +2 -3
- package/src/molecules/ConfirmationModalContent.tsx +1 -1
- package/src/molecules/ConfirmationModalMain.tsx +1 -1
- package/src/molecules/bottom-sheet/components/BottomSheetModal.tsx +1 -3
- package/src/molecules/bottom-sheet/components/filter/FilterBottomSheet.tsx +100 -179
- package/src/molecules/calendar/infrastructure/stores/useCalendarEvents.ts +0 -1
- package/src/molecules/confirmation-modal/useConfirmationModal.ts +1 -1
- package/src/molecules/countdown/components/Countdown.tsx +1 -1
- package/src/molecules/navigation/StackNavigator.tsx +1 -1
- package/src/molecules/navigation/TabsNavigator.tsx +1 -1
- package/src/molecules/navigation/types.ts +2 -2
- package/src/molecules/navigation/utils/AppNavigation.ts +0 -8
- package/src/molecules/splash/components/SplashScreen.tsx +0 -4
- package/src/offline/infrastructure/events/NetworkEvents.ts +2 -2
- package/src/offline/infrastructure/utils/healthCheck.ts +1 -6
- package/src/offline/presentation/hooks/useOffline.ts +1 -2
- package/src/offline/presentation/hooks/useOfflineWithMutations.ts +1 -3
- package/src/onboarding/index.ts +0 -1
- package/src/onboarding/infrastructure/hooks/useOnboardingNavigation.ts +0 -1
- package/src/onboarding/infrastructure/storage/actions/storageHelpers.ts +1 -3
- package/src/onboarding/presentation/hooks/useOnboardingScreenHandlers.ts +2 -4
- package/src/onboarding/presentation/hooks/useOnboardingScreenState.ts +0 -1
- package/src/onboarding/presentation/screens/OnboardingScreen.tsx +0 -3
- package/src/organisms/FormContainer.tsx +1 -1
- package/src/services/api/ApiClient.ts +42 -135
- package/src/storage/cache/domain/Cache.ts +0 -2
- package/src/storage/cache/domain/__tests__/ErrorHandler.test.ts +8 -8
- package/src/storage/cache/infrastructure/TTLCache.ts +0 -3
- package/src/storage/domain/utils/devUtils.ts +3 -6
- package/src/storage/infrastructure/adapters/StorageService.ts +0 -3
- package/src/storage/infrastructure/repositories/BaseStorageOperations.ts +0 -1
- package/src/tanstack/domain/config/QueryClientAccessor.ts +0 -1
- package/src/tanstack/domain/repositories/BaseRepository.ts +4 -4
- package/src/tanstack/domain/repositories/IBaseRepository.ts +3 -5
- package/src/tanstack/domain/repositories/RepositoryFactory.ts +0 -2
- package/src/tanstack/domain/repositories/mixins/repositoryInvalidationMethods.ts +10 -11
- package/src/tanstack/domain/repositories/mixins/repositoryQueryMethods.ts +11 -11
- package/src/tanstack/domain/utils/ErrorHelpers.ts +1 -2
- package/src/tanstack/infrastructure/config/PersisterConfig.ts +6 -13
- package/src/tanstack/infrastructure/config/QueryClientConfig.ts +0 -13
- package/src/tanstack/infrastructure/monitoring/DevMonitorLogger.ts +0 -5
- package/src/tanstack/presentation/hooks/useInvalidateQueries.ts +0 -4
- package/src/tanstack/presentation/hooks/useOptimisticUpdate.ts +0 -2
- package/src/tanstack/presentation/hooks/usePrefetch.ts +18 -119
- package/src/theme/core/CustomColors.ts +4 -122
- package/src/theme/infrastructure/storage/ThemeStorage.ts +0 -1
- package/src/typography/presentation/utils/textColorUtils.ts +36 -163
- 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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
};
|