@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.
Files changed (41) hide show
  1. package/package.json +11 -6
  2. package/src/atoms/GlassView/GlassView.tsx +0 -2
  3. package/src/core/cache/index.ts +3 -2
  4. package/src/core/index.ts +5 -3
  5. package/src/core/repositories/domain/RepositoryUtils.ts +4 -4
  6. package/src/core/repositories/domain/types.ts +2 -2
  7. package/src/hooks/index.ts +22 -25
  8. package/src/infinite-scroll/presentation/hooks/useInfiniteScroll.ts +32 -29
  9. package/src/media/domain/strategies/CameraPickerStrategy.ts +4 -8
  10. package/src/media/domain/strategies/index.ts +1 -1
  11. package/src/media/infrastructure/services/MediaPickerService.ts +3 -14
  12. package/src/media/infrastructure/utils/mediaPickerMappers.ts +29 -6
  13. package/src/molecules/swipe-actions/domain/entities/SwipeAction.ts +0 -1
  14. package/src/offline/index.ts +1 -1
  15. package/src/offline/presentation/hooks/useOffline.ts +0 -8
  16. package/src/storage/README.md +0 -1
  17. package/src/storage/cache/domain/types/README.md +0 -1
  18. package/src/storage/cache/presentation/README.md +0 -1
  19. package/src/storage/cache/presentation/useCachedValue.ts +12 -2
  20. package/src/storage/domain/constants/README.md +0 -1
  21. package/src/storage/infrastructure/adapters/README.md +0 -1
  22. package/src/storage/presentation/hooks/README.md +0 -6
  23. package/src/storage/presentation/hooks/useStorageState.ts +13 -4
  24. package/src/tanstack/domain/repositories/BaseRepository.ts +1 -1
  25. package/src/theme/hooks/useAppDesignTokens.ts +29 -3
  26. package/src/timezone/infrastructure/services/TimezoneProvider.ts +2 -2
  27. package/src/init/index.ts +0 -29
  28. package/src/layouts/ScreenLayout/index.ts +0 -1
  29. package/src/layouts/index.ts +0 -5
  30. package/src/molecules/SearchBar/index.ts +0 -4
  31. package/src/molecules/StepProgress/index.ts +0 -1
  32. package/src/molecules/alerts/index.ts +0 -47
  33. package/src/molecules/bottom-sheet/index.ts +0 -10
  34. package/src/molecules/circular-menu/index.ts +0 -3
  35. package/src/molecules/filter-group/index.ts +0 -3
  36. package/src/molecules/index.ts +0 -38
  37. package/src/molecules/info-grid/index.ts +0 -3
  38. package/src/molecules/swipe-actions/index.ts +0 -6
  39. package/src/presentation/utils/variants/index.ts +0 -6
  40. package/src/timezone/infrastructure/utils/SimpleCache.ts +0 -64
  41. 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.15",
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
- "expo": ">=54.0.0",
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/react": "^19.1.0",
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
 
@@ -8,8 +8,9 @@
8
8
  export { UnifiedCache } from './domain/UnifiedCache';
9
9
  export type { UnifiedCacheConfig } from './domain/UnifiedCache';
10
10
 
11
- export { CleanupStrategy, IntervalCleanupStrategy, TimeoutCleanupStrategy } from './domain/CleanupStrategy';
12
- export type { CleanupType } from './domain/CleanupStrategy';
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, CacheFactory } from './cache/domain/UnifiedCache';
10
- export { CleanupStrategy, IntervalCleanupStrategy, TimeoutCleanupStrategy } from './cache/domain/CleanupStrategy';
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 (formerly cacheTime)
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 merged = mergeRepositoryOptions(options);
46
+ const cache = options.cache ?? {};
47
47
  return {
48
- staleTime: merged.cache.staleTime,
49
- gcTime: merged.cache.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 string[];
56
+ list: (params: ListParams) => readonly unknown[];
57
57
  details: () => readonly string[];
58
- detail: (id: string | number) => readonly string[];
58
+ detail: (id: string | number) => readonly unknown[];
59
59
  };
@@ -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
- useBreakpoint,
39
- useOrientation,
40
- type Breakpoint,
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 UseInfiniteScrollOptions,
59
- type UseInfiniteScrollResult,
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 NetworkStatus,
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
- useAsyncStorage,
88
- useSecureStorage,
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
- useImagePicker,
97
- useImageLibrary,
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
- useLoading,
129
- useLoadingState,
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) loadInitial();
169
- }, [autoLoad, loadInitial]);
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' ? ['videos'] : ['images'];
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 { mapPickerResult } from '../utils/mediaPickerMappers';
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 result = await strategy.launch(options ?? {});
66
- return mapPickerResult(result);
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: ImagePicker.PermissionStatus
18
+ status: string
19
19
  ): MediaLibraryPermission => {
20
20
  switch (status) {
21
- case ImagePicker.PermissionStatus.GRANTED:
21
+ case 'granted':
22
22
  return MediaLibraryPermission.GRANTED;
23
- case ImagePicker.PermissionStatus.DENIED:
24
- return MediaLibraryPermission.DENIED;
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
+ };
@@ -69,7 +69,6 @@ export const DEFAULT_SWIPE_CONFIG: Required<Omit<SwipeableConfig, 'leftActions'
69
69
  friction: 2,
70
70
  };
71
71
 
72
- // Re-export utilities for backward compatibility
73
72
  export {
74
73
  ACTION_PRESETS,
75
74
  getPreset,
@@ -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, configureOffline } from './presentation/hooks/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);
@@ -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
@@ -120,4 +120,3 @@ Presentation layer provides React hooks and components for integrating cache fun
120
120
  - MUST export hooks from index file
121
121
  - MUST provide consistent naming
122
122
  - MUST document hook contracts
123
- - MUST maintain backward compatibility
@@ -2,7 +2,7 @@
2
2
  * useCachedValue Hook
3
3
  */
4
4
 
5
- import { useCallback, useRef, useMemo } from 'react';
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, defaultValue)
43
+ .getItem<T>(keyString, defaultValueRef.current)
38
44
  .then((result) => {
39
45
  if (isMountedRef.current) {
40
- setState(unwrap(result, defaultValue));
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, defaultValue]);
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, this.options.debug ?? __DEV__);
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, customColors, spacingMultiplier, getFontSize),
18
- [themeMode, customColors, spacingMultiplier, getFontSize]
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 { SimpleCache } from '../utils/SimpleCache';
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 SimpleCache<TimezoneInfo[]>(300000); // 5 min cache
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';
@@ -1,5 +0,0 @@
1
- export * from './Container';
2
- export * from './FormLayout';
3
- export * from './Grid';
4
- export * from './ScreenLayout';
5
- export * from './ScreenHeader/ScreenHeader';
@@ -1,4 +0,0 @@
1
- export * from './SearchBar';
2
- export * from './SearchHistory';
3
- export * from './SearchSuggestions';
4
- export * from './types';
@@ -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';
@@ -1,3 +0,0 @@
1
- export * from "./CircularMenu";
2
- export * from "./CircularMenuBackground";
3
- export * from "./CircularMenuCloseButton";
@@ -1,3 +0,0 @@
1
-
2
- export * from './FilterGroup';
3
- export * from './types';
@@ -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,3 +0,0 @@
1
-
2
- export * from './InfoGrid';
3
- export * from './types';
@@ -1,6 +0,0 @@
1
- /**
2
- * Swipe Actions Domain - Barrel Export
3
- */
4
-
5
- export * from './domain/entities/SwipeAction';
6
- export * from './presentation/components/SwipeActionButton';
@@ -1,6 +0,0 @@
1
- /**
2
- * Variant utilities for style management
3
- */
4
-
5
- export * from './core';
6
- export * from './helpers';
@@ -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
- }
@@ -1,6 +0,0 @@
1
- /**
2
- * Utilities - Public API
3
- */
4
-
5
- export * from './clipboard';
6
- export * from './sharing';