@umituz/react-native-design-system 4.27.15 → 4.27.16
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 +11 -6
- package/src/atoms/GlassView/GlassView.tsx +0 -2
- package/src/core/cache/index.ts +3 -2
- package/src/core/index.ts +5 -3
- package/src/core/repositories/domain/RepositoryUtils.ts +4 -4
- package/src/core/repositories/domain/types.ts +2 -2
- package/src/hooks/index.ts +22 -25
- package/src/infinite-scroll/presentation/hooks/useInfiniteScroll.ts +32 -29
- package/src/media/domain/strategies/CameraPickerStrategy.ts +4 -8
- package/src/media/domain/strategies/index.ts +1 -1
- package/src/media/infrastructure/services/MediaPickerService.ts +3 -14
- package/src/media/infrastructure/utils/mediaPickerMappers.ts +29 -6
- package/src/molecules/swipe-actions/domain/entities/SwipeAction.ts +0 -1
- package/src/offline/index.ts +1 -1
- package/src/offline/presentation/hooks/useOffline.ts +0 -8
- package/src/storage/README.md +0 -1
- package/src/storage/cache/domain/types/README.md +0 -1
- package/src/storage/cache/presentation/README.md +0 -1
- package/src/storage/cache/presentation/useCachedValue.ts +12 -2
- package/src/storage/domain/constants/README.md +0 -1
- package/src/storage/infrastructure/adapters/README.md +0 -1
- package/src/storage/presentation/hooks/README.md +0 -6
- package/src/storage/presentation/hooks/useStorageState.ts +13 -4
- package/src/tanstack/domain/repositories/BaseRepository.ts +1 -1
- package/src/theme/hooks/useAppDesignTokens.ts +29 -3
- package/src/timezone/infrastructure/services/TimezoneProvider.ts +2 -2
- package/src/init/index.ts +0 -29
- package/src/layouts/ScreenLayout/index.ts +0 -1
- package/src/layouts/index.ts +0 -5
- package/src/molecules/SearchBar/index.ts +0 -4
- package/src/molecules/StepProgress/index.ts +0 -1
- package/src/molecules/alerts/index.ts +0 -47
- package/src/molecules/bottom-sheet/index.ts +0 -10
- package/src/molecules/circular-menu/index.ts +0 -3
- package/src/molecules/filter-group/index.ts +0 -3
- package/src/molecules/index.ts +0 -38
- package/src/molecules/info-grid/index.ts +0 -3
- package/src/molecules/swipe-actions/index.ts +0 -6
- package/src/presentation/utils/variants/index.ts +0 -6
- package/src/timezone/infrastructure/utils/SimpleCache.ts +0 -64
- package/src/utilities/index.ts +0 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-design-system",
|
|
3
|
-
"version": "4.27.
|
|
3
|
+
"version": "4.27.16",
|
|
4
4
|
"description": "Universal design system for React Native apps - Consolidated package with atoms, molecules, organisms, theme, typography, responsive, safe area, exception, infinite scroll, UUID, image, timezone, offline, onboarding, and loading utilities - TanStack persistence and expo-image-manipulator now lazy loaded",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -208,13 +208,14 @@
|
|
|
208
208
|
"url": "https://github.com/umituz/react-native-design-system"
|
|
209
209
|
},
|
|
210
210
|
"peerDependencies": {
|
|
211
|
-
"
|
|
211
|
+
"@react-native-community/datetimepicker": ">=8.0.0",
|
|
212
212
|
"@react-navigation/bottom-tabs": ">=7.0.0",
|
|
213
213
|
"@react-navigation/native": ">=7.0.0",
|
|
214
214
|
"@react-navigation/stack": ">=7.0.0",
|
|
215
215
|
"@tanstack/query-async-storage-persister": ">=5.0.0",
|
|
216
216
|
"@tanstack/react-query": ">=5.0.0",
|
|
217
217
|
"@tanstack/react-query-persist-client": ">=5.0.0",
|
|
218
|
+
"expo": ">=54.0.0",
|
|
218
219
|
"expo-application": ">=5.0.0",
|
|
219
220
|
"expo-clipboard": ">=8.0.0",
|
|
220
221
|
"expo-crypto": ">=13.0.0",
|
|
@@ -230,10 +231,9 @@
|
|
|
230
231
|
"react": ">=19.0.0",
|
|
231
232
|
"react-native": "*",
|
|
232
233
|
"react-native-gesture-handler": ">=2.20.0",
|
|
234
|
+
"react-native-keyboard-controller": ">=1.0.0",
|
|
233
235
|
"react-native-safe-area-context": ">=5.6.2",
|
|
234
|
-
"zustand": ">=5.0.0"
|
|
235
|
-
"@react-native-community/datetimepicker": ">=8.0.0",
|
|
236
|
-
"react-native-keyboard-controller": ">=1.0.0"
|
|
236
|
+
"zustand": ">=5.0.0"
|
|
237
237
|
},
|
|
238
238
|
"peerDependenciesMeta": {
|
|
239
239
|
"react-native-keyboard-controller": {
|
|
@@ -298,13 +298,18 @@
|
|
|
298
298
|
"@eslint/js": "^9.39.2",
|
|
299
299
|
"@react-native-async-storage/async-storage": "^2.2.0",
|
|
300
300
|
"@react-native-community/datetimepicker": "^8.5.1",
|
|
301
|
+
"@react-navigation/bottom-tabs": "^7.15.5",
|
|
302
|
+
"@react-navigation/native": "^7.1.33",
|
|
303
|
+
"@react-navigation/stack": "^7.8.5",
|
|
301
304
|
"@tanstack/query-async-storage-persister": "^5.66.7",
|
|
302
305
|
"@tanstack/react-query": "^5.66.7",
|
|
303
306
|
"@tanstack/react-query-persist-client": "^5.66.7",
|
|
304
307
|
"@testing-library/react": "^16.3.1",
|
|
305
308
|
"@testing-library/react-native": "^13.3.3",
|
|
306
309
|
"@types/jest": "^30.0.0",
|
|
307
|
-
"@types/
|
|
310
|
+
"@types/node": "^25.5.0",
|
|
311
|
+
"@types/react": "^19.2.14",
|
|
312
|
+
"@types/react-native": "^0.72.8",
|
|
308
313
|
"@typescript-eslint/eslint-plugin": "^8.50.1",
|
|
309
314
|
"@typescript-eslint/parser": "^8.50.1",
|
|
310
315
|
"eslint": "^9.39.2",
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { StyleSheet, ViewStyle, StyleProp, View } from 'react-native';
|
|
3
|
-
// Remove expo-blur import to fix native module error
|
|
4
|
-
// import { BlurView, BlurTint } from 'expo-blur';
|
|
5
3
|
import { useDesignSystemTheme } from '../../theme';
|
|
6
4
|
import { intensityToOpacity } from '../../utils/math';
|
|
7
5
|
|
package/src/core/cache/index.ts
CHANGED
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
export { UnifiedCache } from './domain/UnifiedCache';
|
|
9
9
|
export type { UnifiedCacheConfig } from './domain/UnifiedCache';
|
|
10
10
|
|
|
11
|
-
export { CleanupStrategy
|
|
12
|
-
export
|
|
11
|
+
export type { CleanupStrategy } from './domain/CleanupStrategy';
|
|
12
|
+
export { IntervalCleanupStrategy, TimeoutCleanupStrategy } from './domain/CleanupStrategy';
|
|
13
|
+
export type { CleanupType } from './domain/types';
|
|
13
14
|
|
|
14
15
|
export { CacheFactory } from './infrastructure/CacheFactory';
|
|
15
16
|
|
package/src/core/index.ts
CHANGED
|
@@ -6,10 +6,12 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
// Cache
|
|
9
|
-
export { UnifiedCache
|
|
10
|
-
export {
|
|
9
|
+
export { UnifiedCache } from './cache/domain/UnifiedCache';
|
|
10
|
+
export { CacheFactory } from './cache/infrastructure/CacheFactory';
|
|
11
|
+
export type { CleanupStrategy } from './cache/domain/CleanupStrategy';
|
|
12
|
+
export { IntervalCleanupStrategy, TimeoutCleanupStrategy } from './cache/domain/CleanupStrategy';
|
|
11
13
|
export type { UnifiedCacheConfig } from './cache/domain/UnifiedCache';
|
|
12
|
-
export type { CacheEntry, CacheConfig } from './cache/domain/types';
|
|
14
|
+
export type { CacheEntry, CacheConfig, CleanupType } from './cache/domain/types';
|
|
13
15
|
|
|
14
16
|
// Permissions
|
|
15
17
|
export { PermissionHandler } from './permissions/domain/PermissionHandler';
|
|
@@ -12,7 +12,7 @@ import type { RepositoryOptions, ListParams } from './types';
|
|
|
12
12
|
*/
|
|
13
13
|
const DEFAULT_CACHE_OPTIONS = {
|
|
14
14
|
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
15
|
-
gcTime: 10 * 60 * 1000, // 10 minutes
|
|
15
|
+
gcTime: 10 * 60 * 1000, // 10 minutes
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
/**
|
|
@@ -43,10 +43,10 @@ export function getCacheOptions(options: RepositoryOptions): {
|
|
|
43
43
|
staleTime: number;
|
|
44
44
|
gcTime: number;
|
|
45
45
|
} {
|
|
46
|
-
const
|
|
46
|
+
const cache = options.cache ?? {};
|
|
47
47
|
return {
|
|
48
|
-
staleTime:
|
|
49
|
-
gcTime:
|
|
48
|
+
staleTime: cache.staleTime ?? DEFAULT_CACHE_OPTIONS.staleTime,
|
|
49
|
+
gcTime: cache.gcTime ?? DEFAULT_CACHE_OPTIONS.gcTime,
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
52
|
|
|
@@ -53,7 +53,7 @@ export interface UpdateParams<TVariables> {
|
|
|
53
53
|
export type QueryKeyFactory = {
|
|
54
54
|
all: () => readonly string[];
|
|
55
55
|
lists: () => readonly string[];
|
|
56
|
-
list: (params: ListParams) => readonly
|
|
56
|
+
list: (params: ListParams) => readonly unknown[];
|
|
57
57
|
details: () => readonly string[];
|
|
58
|
-
detail: (id: string | number) => readonly
|
|
58
|
+
detail: (id: string | number) => readonly unknown[];
|
|
59
59
|
};
|
package/src/hooks/index.ts
CHANGED
|
@@ -20,11 +20,6 @@
|
|
|
20
20
|
|
|
21
21
|
export {
|
|
22
22
|
useAppDesignTokens,
|
|
23
|
-
useDesignSystemTheme,
|
|
24
|
-
useTheme,
|
|
25
|
-
useThemedStyles,
|
|
26
|
-
useThemedStyleSheet,
|
|
27
|
-
useCommonStyles,
|
|
28
23
|
} from '../theme/hooks/useAppDesignTokens';
|
|
29
24
|
|
|
30
25
|
export { useTheme as useThemeStore } from '../theme/infrastructure/stores/themeStore';
|
|
@@ -35,9 +30,10 @@ export { useTheme as useThemeStore } from '../theme/infrastructure/stores/themeS
|
|
|
35
30
|
|
|
36
31
|
export {
|
|
37
32
|
useResponsive,
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
useScreenWidth,
|
|
34
|
+
useScreenHeight,
|
|
35
|
+
useScreenDimensions,
|
|
36
|
+
type UseResponsiveReturn,
|
|
41
37
|
} from '../responsive';
|
|
42
38
|
|
|
43
39
|
// =============================================================================
|
|
@@ -45,7 +41,6 @@ export {
|
|
|
45
41
|
// =============================================================================
|
|
46
42
|
|
|
47
43
|
export {
|
|
48
|
-
useSafeArea,
|
|
49
44
|
useSafeAreaInsets,
|
|
50
45
|
} from '../safe-area';
|
|
51
46
|
|
|
@@ -55,8 +50,8 @@ export {
|
|
|
55
50
|
|
|
56
51
|
export {
|
|
57
52
|
useInfiniteScroll,
|
|
58
|
-
type
|
|
59
|
-
type
|
|
53
|
+
type InfiniteScrollConfig,
|
|
54
|
+
type UseInfiniteScrollReturn,
|
|
60
55
|
} from '../infinite-scroll';
|
|
61
56
|
|
|
62
57
|
// =============================================================================
|
|
@@ -65,7 +60,7 @@ export {
|
|
|
65
60
|
|
|
66
61
|
export {
|
|
67
62
|
useOffline,
|
|
68
|
-
type
|
|
63
|
+
type NetworkState,
|
|
69
64
|
} from '../offline';
|
|
70
65
|
|
|
71
66
|
// =============================================================================
|
|
@@ -73,9 +68,11 @@ export {
|
|
|
73
68
|
// =============================================================================
|
|
74
69
|
|
|
75
70
|
export {
|
|
76
|
-
useDeviceContext,
|
|
77
71
|
useDeviceInfo,
|
|
72
|
+
useDeviceCapabilities,
|
|
73
|
+
useDeviceId,
|
|
78
74
|
type DeviceInfo,
|
|
75
|
+
type AnonymousUser,
|
|
79
76
|
} from '../device';
|
|
80
77
|
|
|
81
78
|
// =============================================================================
|
|
@@ -84,8 +81,14 @@ export {
|
|
|
84
81
|
|
|
85
82
|
export {
|
|
86
83
|
useStorage,
|
|
87
|
-
|
|
88
|
-
|
|
84
|
+
useStorageState,
|
|
85
|
+
useStore,
|
|
86
|
+
usePersistentCache,
|
|
87
|
+
useCache,
|
|
88
|
+
useCachedValue,
|
|
89
|
+
useCacheState,
|
|
90
|
+
type PersistentCacheOptions,
|
|
91
|
+
type PersistentCacheResult,
|
|
89
92
|
} from '../storage';
|
|
90
93
|
|
|
91
94
|
// =============================================================================
|
|
@@ -93,10 +96,8 @@ export {
|
|
|
93
96
|
// =============================================================================
|
|
94
97
|
|
|
95
98
|
export {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
useCamera,
|
|
99
|
-
type ImagePickerResult,
|
|
99
|
+
useMedia,
|
|
100
|
+
type MediaPickerResult,
|
|
100
101
|
} from '../media';
|
|
101
102
|
|
|
102
103
|
// =============================================================================
|
|
@@ -105,7 +106,6 @@ export {
|
|
|
105
106
|
|
|
106
107
|
export {
|
|
107
108
|
useTimezone,
|
|
108
|
-
useLocalTime,
|
|
109
109
|
type TimezoneInfo,
|
|
110
110
|
} from '../timezone';
|
|
111
111
|
|
|
@@ -115,9 +115,6 @@ export {
|
|
|
115
115
|
|
|
116
116
|
export {
|
|
117
117
|
useHaptics,
|
|
118
|
-
useImpact,
|
|
119
|
-
useNotification,
|
|
120
|
-
useSelection,
|
|
121
118
|
} from '../haptics';
|
|
122
119
|
|
|
123
120
|
// =============================================================================
|
|
@@ -125,6 +122,6 @@ export {
|
|
|
125
122
|
// =============================================================================
|
|
126
123
|
|
|
127
124
|
export {
|
|
128
|
-
|
|
129
|
-
|
|
125
|
+
useGlobalLoading,
|
|
126
|
+
type LoadingState,
|
|
130
127
|
} from '../loading';
|
|
@@ -67,33 +67,6 @@ export function useInfiniteScroll<T>(
|
|
|
67
67
|
abortControllerRef.current = new AbortController();
|
|
68
68
|
}, []);
|
|
69
69
|
|
|
70
|
-
const loadInitial = useCallback(async () => {
|
|
71
|
-
if (isLoadingRef.current) return;
|
|
72
|
-
isLoadingRef.current = true;
|
|
73
|
-
cancelPendingRequests();
|
|
74
|
-
|
|
75
|
-
if (isMountedRef.current) setState((prev) => ({ ...prev, isLoading: true, error: null }));
|
|
76
|
-
|
|
77
|
-
try {
|
|
78
|
-
const newState = await retryWithBackoff(
|
|
79
|
-
() => loadData(config, initialPage, pageSize, totalItems),
|
|
80
|
-
maxRetries,
|
|
81
|
-
retryDelay,
|
|
82
|
-
);
|
|
83
|
-
|
|
84
|
-
if (isMountedRef.current) {
|
|
85
|
-
setState(newState);
|
|
86
|
-
}
|
|
87
|
-
} catch (error) {
|
|
88
|
-
if (isMountedRef.current) {
|
|
89
|
-
const errorMessage = error instanceof Error ? error.message : "Failed to load data";
|
|
90
|
-
setState((prev) => ({ ...prev, isLoading: false, error: errorMessage }));
|
|
91
|
-
}
|
|
92
|
-
} finally {
|
|
93
|
-
isLoadingRef.current = false;
|
|
94
|
-
}
|
|
95
|
-
}, [config, initialPage, pageSize, totalItems, maxRetries, retryDelay, cancelPendingRequests]);
|
|
96
|
-
|
|
97
70
|
const loadMore = useCallback(async () => {
|
|
98
71
|
// Get fresh state from ref to avoid stale closure
|
|
99
72
|
const currentState = stateRef.current;
|
|
@@ -165,8 +138,38 @@ export function useInfiniteScroll<T>(
|
|
|
165
138
|
}, [initialPage, totalItems, cancelPendingRequests]);
|
|
166
139
|
|
|
167
140
|
useEffect(() => {
|
|
168
|
-
if (autoLoad)
|
|
169
|
-
|
|
141
|
+
if (autoLoad) {
|
|
142
|
+
const initialize = async () => {
|
|
143
|
+
if (isLoadingRef.current) return;
|
|
144
|
+
|
|
145
|
+
isLoadingRef.current = true;
|
|
146
|
+
cancelPendingRequests();
|
|
147
|
+
|
|
148
|
+
if (isMountedRef.current) setState((prev) => ({ ...prev, isLoading: true, error: null }));
|
|
149
|
+
|
|
150
|
+
try {
|
|
151
|
+
const newState = await retryWithBackoff(
|
|
152
|
+
() => loadData(config, initialPage, pageSize, totalItems),
|
|
153
|
+
maxRetries,
|
|
154
|
+
retryDelay,
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
if (isMountedRef.current) {
|
|
158
|
+
setState(newState);
|
|
159
|
+
}
|
|
160
|
+
} catch (error) {
|
|
161
|
+
if (isMountedRef.current) {
|
|
162
|
+
const errorMessage = error instanceof Error ? error.message : "Failed to load data";
|
|
163
|
+
setState((prev) => ({ ...prev, isLoading: false, error: errorMessage }));
|
|
164
|
+
}
|
|
165
|
+
} finally {
|
|
166
|
+
isLoadingRef.current = false;
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
initialize();
|
|
170
|
+
}
|
|
171
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
172
|
+
}, [autoLoad]);
|
|
170
173
|
|
|
171
174
|
const canLoadMore = state.hasMore && !state.isLoadingMore && !state.isLoading;
|
|
172
175
|
|
|
@@ -32,8 +32,10 @@ export class CameraPickerStrategy implements PickerStrategy {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
async launch(options: LaunchOptions): Promise<any> {
|
|
35
|
-
const mediaTypes =
|
|
36
|
-
this.config.mediaType === 'videos'
|
|
35
|
+
const mediaTypes: ImagePicker.MediaTypeOptions =
|
|
36
|
+
this.config.mediaType === 'videos'
|
|
37
|
+
? ImagePicker.MediaTypeOptions.Videos
|
|
38
|
+
: ImagePicker.MediaTypeOptions.Images;
|
|
37
39
|
|
|
38
40
|
const launchOptions: ImagePicker.ImagePickerOptions = {
|
|
39
41
|
mediaTypes,
|
|
@@ -52,12 +54,6 @@ export class CameraPickerStrategy implements PickerStrategy {
|
|
|
52
54
|
if (options.videoMaxDuration !== undefined) {
|
|
53
55
|
launchOptions.videoMaxDuration = options.videoMaxDuration;
|
|
54
56
|
}
|
|
55
|
-
if (options.videoMaxBitrate !== undefined) {
|
|
56
|
-
launchOptions.videoMaxBitrate = options.videoMaxBitrate;
|
|
57
|
-
}
|
|
58
|
-
if (options.videoQuality) {
|
|
59
|
-
launchOptions.videoQuality = options.videoQuality;
|
|
60
|
-
}
|
|
61
57
|
}
|
|
62
58
|
|
|
63
59
|
return ImagePicker.launchCameraAsync(launchOptions);
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Strategy pattern implementations for different picker types.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
export { PickerStrategy } from './PickerStrategy';
|
|
7
|
+
export type { PickerStrategy } from './PickerStrategy';
|
|
8
8
|
export type { LaunchOptions, PickerLaunchResult } from './PickerStrategy';
|
|
9
9
|
|
|
10
10
|
export { CameraPickerStrategy } from './CameraPickerStrategy';
|
|
@@ -16,9 +16,8 @@ import type {
|
|
|
16
16
|
import {
|
|
17
17
|
MediaType,
|
|
18
18
|
MediaValidationError,
|
|
19
|
-
MEDIA_CONSTANTS,
|
|
20
19
|
} from '../../domain/entities/Media';
|
|
21
|
-
import {
|
|
20
|
+
import { mapPickerResultFromStrategy } from '../utils/mediaPickerMappers';
|
|
22
21
|
import { PermissionManager } from '../utils/PermissionManager';
|
|
23
22
|
import { FileValidator } from '../../domain/utils/FileValidator';
|
|
24
23
|
import { ErrorHandler } from '../../../utils/errors';
|
|
@@ -62,8 +61,8 @@ export class MediaPickerService {
|
|
|
62
61
|
}
|
|
63
62
|
|
|
64
63
|
try {
|
|
65
|
-
const
|
|
66
|
-
return
|
|
64
|
+
const pickerResult = await strategy.launch(options ?? {});
|
|
65
|
+
return mapPickerResultFromStrategy(pickerResult);
|
|
67
66
|
} catch (error) {
|
|
68
67
|
ErrorHandler.handleAndLog(error, 'launchMediaPicker', {
|
|
69
68
|
strategy: strategy.name,
|
|
@@ -178,14 +177,4 @@ export class MediaPickerService {
|
|
|
178
177
|
mediaTypes: MediaType.ALL,
|
|
179
178
|
});
|
|
180
179
|
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Legacy method for backward compatibility
|
|
184
|
-
* @deprecated Use pickSingleImage instead
|
|
185
|
-
*/
|
|
186
|
-
static async pickImage(
|
|
187
|
-
options?: MediaPickerOptions
|
|
188
|
-
): Promise<MediaPickerResult> {
|
|
189
|
-
return this.pickFromLibrary(options);
|
|
190
|
-
}
|
|
191
180
|
}
|
|
@@ -15,15 +15,13 @@ import {
|
|
|
15
15
|
* Map expo-image-picker permission status to MediaLibraryPermission
|
|
16
16
|
*/
|
|
17
17
|
export const mapPermissionStatus = (
|
|
18
|
-
status:
|
|
18
|
+
status: string
|
|
19
19
|
): MediaLibraryPermission => {
|
|
20
20
|
switch (status) {
|
|
21
|
-
case
|
|
21
|
+
case 'granted':
|
|
22
22
|
return MediaLibraryPermission.GRANTED;
|
|
23
|
-
case
|
|
24
|
-
|
|
25
|
-
case ImagePicker.PermissionStatus.UNDETERMINED:
|
|
26
|
-
return MediaLibraryPermission.DENIED;
|
|
23
|
+
case 'denied':
|
|
24
|
+
case 'undetermined':
|
|
27
25
|
default:
|
|
28
26
|
return MediaLibraryPermission.DENIED;
|
|
29
27
|
}
|
|
@@ -74,3 +72,28 @@ export const mapPickerResult = (
|
|
|
74
72
|
assets,
|
|
75
73
|
};
|
|
76
74
|
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Map PickerStrategy result to MediaPickerResult
|
|
78
|
+
*/
|
|
79
|
+
export const mapPickerResultFromStrategy = (
|
|
80
|
+
result: { canceled: boolean; assets?: Array<{ uri: string; width?: number; height?: number; type?: 'image' | 'video'; duration?: number; fileSize?: number }> }
|
|
81
|
+
): MediaPickerResult => {
|
|
82
|
+
if (result.canceled) {
|
|
83
|
+
return { canceled: true };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const assets: MediaAsset[] = (result.assets ?? []).map((asset) => ({
|
|
87
|
+
uri: asset.uri,
|
|
88
|
+
width: asset.width ?? 0,
|
|
89
|
+
height: asset.height ?? 0,
|
|
90
|
+
type: asset.type === 'video' ? MediaType.VIDEO : MediaType.IMAGE,
|
|
91
|
+
fileSize: asset.fileSize,
|
|
92
|
+
duration: asset.duration,
|
|
93
|
+
}));
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
canceled: false,
|
|
97
|
+
assets,
|
|
98
|
+
};
|
|
99
|
+
};
|
package/src/offline/index.ts
CHANGED
|
@@ -17,7 +17,7 @@ export { useOfflineStore } from './infrastructure/storage/OfflineStore';
|
|
|
17
17
|
export { useOfflineConfigStore } from './infrastructure/storage/OfflineConfigStore';
|
|
18
18
|
|
|
19
19
|
// Hooks
|
|
20
|
-
export { useOffline
|
|
20
|
+
export { useOffline } from './presentation/hooks/useOffline';
|
|
21
21
|
export { useOfflineState } from './presentation/hooks/useOfflineState';
|
|
22
22
|
export { useOfflineWithMutations } from './presentation/hooks/useOfflineWithMutations';
|
|
23
23
|
|
|
@@ -38,14 +38,6 @@ const toNetworkState = (state: ExpoNetworkState): NetworkState => ({
|
|
|
38
38
|
details: null,
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
-
/**
|
|
42
|
-
* Configure offline settings globally
|
|
43
|
-
* This is a facade over the config store for backward compatibility
|
|
44
|
-
*/
|
|
45
|
-
export const configureOffline = (config: OfflineConfig): void => {
|
|
46
|
-
useOfflineConfigStore.getState().setConfig(config);
|
|
47
|
-
};
|
|
48
|
-
|
|
49
41
|
export const useOffline = (config?: OfflineConfig) => {
|
|
50
42
|
const store = useOfflineStore();
|
|
51
43
|
const globalConfig = useOfflineConfigStore((state) => state.config);
|
package/src/storage/README.md
CHANGED
|
@@ -118,7 +118,6 @@ Clean Architecture with DDD principles:
|
|
|
118
118
|
- MUST export from index.ts at root level
|
|
119
119
|
- MUST organize exports by module
|
|
120
120
|
- MUST provide TypeScript types
|
|
121
|
-
- MUST maintain backward compatibility
|
|
122
121
|
- MUST not export internal utilities
|
|
123
122
|
|
|
124
123
|
### File Organization
|
|
@@ -103,5 +103,4 @@ TypeScript type definitions for cache entries, configuration, statistics, and ev
|
|
|
103
103
|
### Export Rules
|
|
104
104
|
- MUST export all public types
|
|
105
105
|
- MUST use `type` keyword for type-only exports
|
|
106
|
-
- MUST maintain backward compatibility
|
|
107
106
|
- MUST document type changes
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* useCachedValue Hook
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { useCallback,
|
|
5
|
+
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
6
6
|
import { cacheManager } from '../domain/CacheManager';
|
|
7
7
|
import type { CacheConfig } from '../domain/types/Cache';
|
|
8
8
|
import { useAsyncOperation } from '../../../utils/hooks';
|
|
@@ -16,6 +16,15 @@ export function useCachedValue<T>(
|
|
|
16
16
|
const fetcherRef = useRef(fetcher);
|
|
17
17
|
const configRef = useRef(config);
|
|
18
18
|
|
|
19
|
+
// Update refs when props change
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
fetcherRef.current = fetcher;
|
|
22
|
+
}, [fetcher]);
|
|
23
|
+
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
configRef.current = config;
|
|
26
|
+
}, [config]);
|
|
27
|
+
|
|
19
28
|
const { data: value, isLoading, error, execute, setData } = useAsyncOperation<T | undefined, Error>(
|
|
20
29
|
async () => {
|
|
21
30
|
const cache = cacheManager.getCache<T>(cacheName, configRef.current);
|
|
@@ -55,8 +64,9 @@ export function useCachedValue<T>(
|
|
|
55
64
|
}, [cacheName, setData]);
|
|
56
65
|
|
|
57
66
|
const refetch = useCallback(() => {
|
|
67
|
+
// Clear data first, then execute on next tick
|
|
58
68
|
setData(undefined);
|
|
59
|
-
execute();
|
|
69
|
+
Promise.resolve().then(() => execute());
|
|
60
70
|
}, [execute, setData]);
|
|
61
71
|
|
|
62
72
|
return useMemo(() => ({
|
|
@@ -84,7 +84,6 @@ Constant values for time-based calculations and default configuration. Located a
|
|
|
84
84
|
- MUST increment CACHE_VERSION on schema changes
|
|
85
85
|
- MUST implement migration for old versions
|
|
86
86
|
- MUST document breaking changes
|
|
87
|
-
- MUST support backward compatibility where possible
|
|
88
87
|
|
|
89
88
|
### Export Rules
|
|
90
89
|
- MUST export all constants
|
|
@@ -137,7 +137,6 @@ Storage adapter implementations for Zustand persist middleware. Located at `src/
|
|
|
137
137
|
- MUST migrate data on read
|
|
138
138
|
- MUST clean up old data after migration
|
|
139
139
|
- MUST handle migration failures
|
|
140
|
-
- MUST be backward compatible
|
|
141
140
|
|
|
142
141
|
### Error Handling
|
|
143
142
|
- MUST catch all exceptions in adapter methods
|
|
@@ -120,9 +120,3 @@ This directory contains React hooks that integrate storage and cache functionali
|
|
|
120
120
|
- MUST use `useMemo` for computed values
|
|
121
121
|
- MUST implement proper dependency arrays
|
|
122
122
|
- MUST avoid unnecessary re-renders
|
|
123
|
-
|
|
124
|
-
### Deprecation
|
|
125
|
-
- MUST document deprecated hooks
|
|
126
|
-
- MUST provide migration path for deprecated hooks
|
|
127
|
-
- MUST maintain backward compatibility when possible
|
|
128
|
-
- MUST remove deprecated hooks after major version bump
|
|
@@ -28,20 +28,29 @@ export const useStorageState = <T>(
|
|
|
28
28
|
const [state, setState] = useState<T>(defaultValue);
|
|
29
29
|
const [isLoading, setIsLoading] = useState(true);
|
|
30
30
|
const isMountedRef = useRef(true);
|
|
31
|
+
const defaultValueRef = useRef(defaultValue);
|
|
32
|
+
|
|
33
|
+
// Update ref when defaultValue changes
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
defaultValueRef.current = defaultValue;
|
|
36
|
+
}, [defaultValue]);
|
|
31
37
|
|
|
32
38
|
useEffect(() => {
|
|
33
39
|
isMountedRef.current = true;
|
|
34
40
|
setIsLoading(true);
|
|
35
41
|
|
|
36
42
|
storageRepository
|
|
37
|
-
.getItem<T>(keyString,
|
|
43
|
+
.getItem<T>(keyString, defaultValueRef.current)
|
|
38
44
|
.then((result) => {
|
|
39
45
|
if (isMountedRef.current) {
|
|
40
|
-
setState(unwrap(result,
|
|
46
|
+
setState(unwrap(result, defaultValueRef.current));
|
|
41
47
|
}
|
|
42
48
|
})
|
|
43
|
-
.catch(() => {
|
|
49
|
+
.catch((error) => {
|
|
44
50
|
// Keep defaultValue on error
|
|
51
|
+
if (__DEV__) {
|
|
52
|
+
console.warn('[useStorageState] Failed to load from storage:', error);
|
|
53
|
+
}
|
|
45
54
|
})
|
|
46
55
|
.finally(() => {
|
|
47
56
|
if (isMountedRef.current) {
|
|
@@ -52,7 +61,7 @@ export const useStorageState = <T>(
|
|
|
52
61
|
return () => {
|
|
53
62
|
isMountedRef.current = false;
|
|
54
63
|
};
|
|
55
|
-
}, [keyString
|
|
64
|
+
}, [keyString]);
|
|
56
65
|
|
|
57
66
|
// Update state and persist to storage
|
|
58
67
|
const updateState = useCallback(
|
|
@@ -79,7 +79,7 @@ export abstract class BaseRepository<
|
|
|
79
79
|
this.resource = resource;
|
|
80
80
|
this.options = mergeRepositoryOptions(options);
|
|
81
81
|
this.keys = createQueryKeyFactory(this.resource);
|
|
82
|
-
this.log = createRepositoryLogger(resource,
|
|
82
|
+
this.log = createRepositoryLogger(resource, __DEV__);
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
/**
|
|
@@ -1,8 +1,28 @@
|
|
|
1
|
-
import { useMemo } from 'react';
|
|
1
|
+
import { useMemo, useRef } from 'react';
|
|
2
2
|
import { useTheme } from '../infrastructure/stores/themeStore';
|
|
3
3
|
import { createDesignTokens } from '../core/TokenFactory';
|
|
4
4
|
import { useResponsive } from '../../responsive/useResponsive';
|
|
5
5
|
import { type DesignTokens } from '../types/ThemeTypes';
|
|
6
|
+
import type { CustomThemeColors } from '../core/CustomColors';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Shallow equality check for CustomThemeColors
|
|
10
|
+
*/
|
|
11
|
+
function areCustomColorsEqual(a?: CustomThemeColors, b?: CustomThemeColors): boolean {
|
|
12
|
+
if (a === b) return true;
|
|
13
|
+
if (!a || !b) return false;
|
|
14
|
+
|
|
15
|
+
const keysA = Object.keys(a) as (keyof CustomThemeColors)[];
|
|
16
|
+
const keysB = Object.keys(b) as (keyof CustomThemeColors)[];
|
|
17
|
+
|
|
18
|
+
if (keysA.length !== keysB.length) return false;
|
|
19
|
+
|
|
20
|
+
for (const key of keysA) {
|
|
21
|
+
if (a[key] !== b[key]) return false;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
6
26
|
|
|
7
27
|
/**
|
|
8
28
|
* Hook to access current design tokens (colors, spacing, typography, etc.)
|
|
@@ -13,8 +33,14 @@ export const useAppDesignTokens = (): DesignTokens => {
|
|
|
13
33
|
const { themeMode, customColors } = useTheme();
|
|
14
34
|
const { spacingMultiplier, getFontSize } = useResponsive();
|
|
15
35
|
|
|
36
|
+
// Stabilize customColors reference to prevent unnecessary re-computation
|
|
37
|
+
const customColorsRef = useRef(customColors);
|
|
38
|
+
if (!areCustomColorsEqual(customColorsRef.current, customColors)) {
|
|
39
|
+
customColorsRef.current = customColors;
|
|
40
|
+
}
|
|
41
|
+
|
|
16
42
|
return useMemo(
|
|
17
|
-
() => createDesignTokens(themeMode,
|
|
18
|
-
[themeMode,
|
|
43
|
+
() => createDesignTokens(themeMode, customColorsRef.current, spacingMultiplier, getFontSize),
|
|
44
|
+
[themeMode, spacingMultiplier, getFontSize]
|
|
19
45
|
);
|
|
20
46
|
};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { TimezoneInfo } from '../../domain/entities/Timezone';
|
|
2
|
-
import {
|
|
2
|
+
import { UnifiedCache } from '../../../core/cache/domain/UnifiedCache';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* TimezoneProvider
|
|
6
6
|
* Responsible for discovering device timezone and providing available timezones
|
|
7
7
|
*/
|
|
8
8
|
export class TimezoneProvider {
|
|
9
|
-
private cache = new
|
|
9
|
+
private cache = new UnifiedCache<TimezoneInfo[]>({ defaultTTL: 300000 }); // 5 min cache
|
|
10
10
|
/**
|
|
11
11
|
* Get current device timezone using Intl API
|
|
12
12
|
*/
|
package/src/init/index.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* App Initialization Module
|
|
3
|
-
*
|
|
4
|
-
* Provides utilities for app initialization:
|
|
5
|
-
* - createAppInitializer: Factory for creating app initializers
|
|
6
|
-
* - useAppInitialization: Hook for managing initialization state
|
|
7
|
-
* - createEnvConfig: Environment configuration factory
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
// App Initializer
|
|
11
|
-
export {
|
|
12
|
-
createAppInitializer,
|
|
13
|
-
createInitModule,
|
|
14
|
-
} from "./createAppInitializer";
|
|
15
|
-
|
|
16
|
-
// Initialization Hook
|
|
17
|
-
export { useAppInitialization } from "./useAppInitialization";
|
|
18
|
-
|
|
19
|
-
// Environment Configuration
|
|
20
|
-
export * from "./env";
|
|
21
|
-
|
|
22
|
-
// Types
|
|
23
|
-
export type {
|
|
24
|
-
InitModule,
|
|
25
|
-
AppInitializerConfig,
|
|
26
|
-
AppInitializerResult,
|
|
27
|
-
UseAppInitializationOptions,
|
|
28
|
-
UseAppInitializationReturn,
|
|
29
|
-
} from "./types";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './ScreenLayout';
|
package/src/layouts/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./StepProgress";
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Alerts Molecule - Public API
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export * from './AlertTypes';
|
|
6
|
-
export { useAlertStore } from './AlertStore';
|
|
7
|
-
export { AlertService } from './AlertService';
|
|
8
|
-
export { AlertBanner } from './AlertBanner';
|
|
9
|
-
export { AlertToast } from './AlertToast';
|
|
10
|
-
export { AlertInline } from './AlertInline';
|
|
11
|
-
export { AlertModal } from './AlertModal';
|
|
12
|
-
export { AlertContainer } from './AlertContainer';
|
|
13
|
-
export { AlertProvider } from './AlertProvider';
|
|
14
|
-
export { useAlert } from './useAlert';
|
|
15
|
-
|
|
16
|
-
import { AlertService } from './AlertService';
|
|
17
|
-
import { useAlertStore } from './AlertStore';
|
|
18
|
-
import { AlertOptions } from './AlertTypes';
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Convenience alert service for use outside of components
|
|
22
|
-
*/
|
|
23
|
-
export const alertService = {
|
|
24
|
-
error: (title: string, message?: string, options?: AlertOptions) => {
|
|
25
|
-
const alert = AlertService.createErrorAlert(title, message, options);
|
|
26
|
-
useAlertStore.getState().addAlert(alert);
|
|
27
|
-
return alert.id;
|
|
28
|
-
},
|
|
29
|
-
success: (title: string, message?: string, options?: AlertOptions) => {
|
|
30
|
-
const alert = AlertService.createSuccessAlert(title, message, options);
|
|
31
|
-
useAlertStore.getState().addAlert(alert);
|
|
32
|
-
return alert.id;
|
|
33
|
-
},
|
|
34
|
-
warning: (title: string, message?: string, options?: AlertOptions) => {
|
|
35
|
-
const alert = AlertService.createWarningAlert(title, message, options);
|
|
36
|
-
useAlertStore.getState().addAlert(alert);
|
|
37
|
-
return alert.id;
|
|
38
|
-
},
|
|
39
|
-
info: (title: string, message?: string, options?: AlertOptions) => {
|
|
40
|
-
const alert = AlertService.createInfoAlert(title, message, options);
|
|
41
|
-
useAlertStore.getState().addAlert(alert);
|
|
42
|
-
return alert.id;
|
|
43
|
-
},
|
|
44
|
-
dismiss: (id: string) => {
|
|
45
|
-
useAlertStore.getState().dismissAlert(id);
|
|
46
|
-
},
|
|
47
|
-
};
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export * from './components/BottomSheet';
|
|
2
|
-
export * from './components/BottomSheetModal';
|
|
3
|
-
|
|
4
|
-
export * from './components/filter/FilterBottomSheet';
|
|
5
|
-
export * from './components/filter/FilterSheet';
|
|
6
|
-
export * from './hooks/useBottomSheet';
|
|
7
|
-
export * from './hooks/useBottomSheetModal';
|
|
8
|
-
export * from './hooks/useListFilters';
|
|
9
|
-
export * from './types/BottomSheet';
|
|
10
|
-
export * from './types/Filter';
|
package/src/molecules/index.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Molecules - Composite UI components
|
|
3
|
-
* Built from atoms following atomic design principles
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// Component exports
|
|
7
|
-
export * from './avatar';
|
|
8
|
-
export * from './bottom-sheet';
|
|
9
|
-
export { FormField, type FormFieldProps } from './FormField';
|
|
10
|
-
export { ListItem, type ListItemProps } from './ListItem';
|
|
11
|
-
export { SearchBar, type SearchBarProps } from './SearchBar';
|
|
12
|
-
export { IconContainer } from './IconContainer';
|
|
13
|
-
export { BaseModal, type BaseModalProps } from './BaseModal';
|
|
14
|
-
export { ConfirmationModal } from './ConfirmationModalMain';
|
|
15
|
-
export { useConfirmationModal } from './confirmation-modal/useConfirmationModal';
|
|
16
|
-
|
|
17
|
-
// Other components
|
|
18
|
-
export * from './Divider/Divider';
|
|
19
|
-
export * from './Divider/types';
|
|
20
|
-
export * from './StepProgress';
|
|
21
|
-
export * from './List';
|
|
22
|
-
export * from './alerts';
|
|
23
|
-
export * from './calendar';
|
|
24
|
-
export * from './swipe-actions';
|
|
25
|
-
export * from './navigation';
|
|
26
|
-
export * from './long-press-menu';
|
|
27
|
-
export * from './StepHeader';
|
|
28
|
-
export * from './emoji';
|
|
29
|
-
export * from './countdown';
|
|
30
|
-
export * from './splash';
|
|
31
|
-
export * from './filter-group';
|
|
32
|
-
export * from './action-footer/ActionFooter';
|
|
33
|
-
export * from './action-footer/types';
|
|
34
|
-
export * from './hero-section/HeroSection';
|
|
35
|
-
export * from './hero-section/types';
|
|
36
|
-
export * from './info-grid';
|
|
37
|
-
export * from './circular-menu';
|
|
38
|
-
export * from './icon-grid';
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SimpleCache (Backward Compatibility Wrapper)
|
|
3
|
-
*
|
|
4
|
-
* @deprecated Use UnifiedCache from core/cache instead.
|
|
5
|
-
* This wrapper maintains backward compatibility while migrating to UnifiedCache.
|
|
6
|
-
*
|
|
7
|
-
* Lightweight in-memory cache for performance optimization.
|
|
8
|
-
* Now implemented using UnifiedCache with timeout-based cleanup strategy.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { UnifiedCache } from '../../../core/cache/domain/UnifiedCache';
|
|
12
|
-
import { TimeoutCleanupStrategy } from '../../../core/cache/domain/CleanupStrategy';
|
|
13
|
-
import { ONE_MINUTE_MS } from '../../../utils/constants/TimeConstants';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* SimpleCache - Wrapper around UnifiedCache for backward compatibility
|
|
17
|
-
*
|
|
18
|
-
* @example
|
|
19
|
-
* ```ts
|
|
20
|
-
* // Old usage (still works):
|
|
21
|
-
* const cache = new SimpleCache<string>(60000);
|
|
22
|
-
*
|
|
23
|
-
* // New usage (recommended):
|
|
24
|
-
* import { CacheFactory } from '../../../core/cache';
|
|
25
|
-
* const cache = CacheFactory.createTimeoutCache(60000);
|
|
26
|
-
* ```
|
|
27
|
-
*/
|
|
28
|
-
export class SimpleCache<T> {
|
|
29
|
-
private cache: UnifiedCache<T>;
|
|
30
|
-
|
|
31
|
-
constructor(defaultTTL: number = ONE_MINUTE_MS) {
|
|
32
|
-
this.cache = new UnifiedCache<T>({
|
|
33
|
-
defaultTTL,
|
|
34
|
-
cleanupStrategy: new TimeoutCleanupStrategy(ONE_MINUTE_MS),
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Destroy the cache and stop cleanup timer
|
|
40
|
-
*/
|
|
41
|
-
destroy(): void {
|
|
42
|
-
this.cache.destroy();
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
set(key: string, value: T, ttl?: number): void {
|
|
46
|
-
this.cache.set(key, value, ttl);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
get(key: string): T | undefined {
|
|
50
|
-
return this.cache.get(key);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
has(key: string): boolean {
|
|
54
|
-
return this.cache.has(key);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
clear(): void {
|
|
58
|
-
this.cache.clear();
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
delete(key: string): void {
|
|
62
|
-
this.cache.delete(key);
|
|
63
|
-
}
|
|
64
|
-
}
|